Haz click para abrir el mapa de Madrid de Airbnb

library(caret)
library(dplyr)
library(ggplot2)
library(stringr)
library(readr)
library(batman)
library(knitr)
library(tidyr)
library(PASWR2)
library(scales)
library(nortest)
library(kableExtra) # sudo apt install libfontconfig1-dev
library(cowplot)
library(mice)
library(VIM)
library(ggcorrplot)
library(psych)
library(ipred)
library(car)
library(ggfortify)
library(geojsonio)
library(gridExtra)
library(shiny)
library(GGally)
library(RColorBrewer)
library(ggExtra)
library(DMwR) # install.packages(c("zoo","xts","quantmod")), luego instala ROCR, luego install.packages( "Path/To/DMwR_0.4.1.tar.gz", repos=NULL, type="source" )
library(geosphere)
library(MASS)
library(gvlma)
library('glmnet')
library(leaps)



Definición de objetivos

Para la realización de esta práctica se ha seleccionado el dataset listings.csv (Airbnb Madrid, 2021-09-10), un conjunto de datos obtenido de insideairbnb.com. Puede ser descargado a través de este enlace.

El objetivo general de esta práctica es proponer un modelo de regresión lineal multivariante para predecir el precio por noche de un espacio ofertado en la plataforma AirBnb y situado en Madrid.

Dicho objetivo, a su vez se dividirá en los siguientes pasos:

  1. Selección preliminar de variables.
  2. Separación del conjunto de datos en dos grupos: Training (70% de los datos) y Test (30% de los datos)
  3. Realización de un análisis exploratorio univariante de los datos.
  4. Estudio e imputación de datos faltantes.
  5. Realización de un análisis exploratorio multivariante de los datos.
  6. Transformaciones necesarias a cada una de las variables para poder ser utilizadas en la regresión.
  7. Ajuste, aplicación y evaluación de un modelo de regresión lineal múltiple con las variables seleccionadas para la predicción de la variable \(price\).



Selección preliminar de variables

El conjunto de datos original está formado por un total de 18909 datos y 74 variables, que son:

id
listing_url
scrape_id
last_scraped
name
description
neighborhood_overview
picture_url
host_id
host_url
host_name
host_since
host_location
host_about
host_response_time
host_response_rate
host_acceptance_rate
host_is_superhost
host_thumbnail_url
host_picture_url
host_neighbourhood
host_listings_count
host_total_listings_count
host_verifications
host_has_profile_pic
host_identity_verified
neighbourhood
neighbourhood_cleansed
neighbourhood_group_cleansed
latitude
longitude
property_type
room_type
accommodates
bathrooms
bathrooms_text
bedrooms
beds
amenities
price
minimum_nights
maximum_nights
minimum_minimum_nights
maximum_minimum_nights
minimum_maximum_nights
maximum_maximum_nights
minimum_nights_avg_ntm
maximum_nights_avg_ntm
calendar_updated
has_availability
availability_30
availability_60
availability_90
availability_365
calendar_last_scraped
number_of_reviews
number_of_reviews_ltm
number_of_reviews_l30d
first_review
last_review
review_scores_rating
review_scores_accuracy
review_scores_cleanliness
review_scores_checkin
review_scores_communication
review_scores_location
review_scores_value
license
instant_bookable
calculated_host_listings_count
calculated_host_listings_count_entire_homes
calculated_host_listings_count_private_rooms
calculated_host_listings_count_shared_rooms
reviews_per_month


Basándonos en un conocimiento preliminar proporcionado por la plataforma sobre el contenido de las variables, se seleccionarán aquellas consideradas de potencial interés para la realización del modelo:

data <- RawData %>%
   dplyr::select(id, host_id, host_since, host_is_superhost, description, neighbourhood_group_cleansed, latitude, longitude, room_type, accommodates, bedrooms, beds, price, minimum_nights, minimum_nights_avg_ntm, maximum_nights_avg_ntm, availability_365, last_review, review_scores_rating, review_scores_accuracy, review_scores_cleanliness, review_scores_checkin, review_scores_communication, review_scores_location, review_scores_value, reviews_per_month)

# Corrección de tipos

data$host_since <- as.Date(data$host_since)
data$last_review <- as.Date(data$last_review)

data$host_is_superhost <- as.character(data$host_is_superhost)
data$host_is_superhost[which(data$host_is_superhost == "")] <- NA
data$host_is_superhost[which(data$host_is_superhost == "t")] <- "true"
data$host_is_superhost[which(data$host_is_superhost == "f")] <- "false"
data$host_is_superhost <- to_logical(data$host_is_superhost)

data$price <- as.character(data$price)
data$price<-parse_number(data$price)

data$description <- as.character(data$description)
data$description[which(data$description == "")] <- NA


# Eliminación de observaciones inverosímiles

data <- data[data$price>0 & data$accommodates>0,]


# Selección de variables de interés
   
voi <- data.frame("Variable" = c("host_id", "host_since", "host_is_superhost", "description", "neighbourhood_group_cleansed", "latitude", "longitude", "room_type", "accommodates", "bedrooms", "beds", "price", "minimum_nights", "minimum_nights_avg_ntm", "maximum_nights_avg_ntm", "availability_365", "last_review", "review_scores_rating", "review_scores_accuracy", "review_scores_cleanliness", "review_scores_checkin", "review_scores_communication", "review_scores_location", "review_scores_value", "reviews_per_month"),
         
                  "Definición" = c("identificador único de cada arrendador", "fecha en que el arrendador se dio de alta en la plataforma","indicador lógico de si el arrendador tiene excelentes puntuaciones","descripción del espacio alquilable","distrito en que se encuentra el espacio alquilable","coordenada de latitud del espacio alquilable","coordenada de longitud del espacio alquilable","tipo de habitación","capacidad máxima del espacio","número de cuartos de baño","número de camas de la habitación","precio por noche en moneda local","mínimo de noches por estancia","promedio de mínimo de noches durante los próximos 365 días","promedio de máximo de noches durante los próximos 365 días","disponibilidad del espacio durante los próximos 365 días","fecha de la última puntuación","puntuación general del espacio","puntuación sobre la realidad/descripción del espacio","puntuación sobre la limpieza del espacio","puntuación sobre el checkin","puntuación sobre lo bien que está comunicado el espacio","puntuación de la localización del espacio","puntuación del valor del espacio","media de número de reviews por espacio durante un mes"))

voi$Tipo <- sapply(data[,voi$Variable],class)
voi <- voi[,c(1,3,2)]

kable(voi) %>% kable_styling("striped") %>%
  scroll_box(width = "100%", height = "350px")
Variable Tipo Definición
host_id integer identificador único de cada arrendador
host_since Date fecha en que el arrendador se dio de alta en la plataforma
host_is_superhost logical indicador lógico de si el arrendador tiene excelentes puntuaciones
description character descripción del espacio alquilable
neighbourhood_group_cleansed character distrito en que se encuentra el espacio alquilable
latitude numeric coordenada de latitud del espacio alquilable
longitude numeric coordenada de longitud del espacio alquilable
room_type character tipo de habitación
accommodates integer capacidad máxima del espacio
bedrooms integer número de cuartos de baño
beds integer número de camas de la habitación
price numeric precio por noche en moneda local
minimum_nights integer mínimo de noches por estancia
minimum_nights_avg_ntm numeric promedio de mínimo de noches durante los próximos 365 días
maximum_nights_avg_ntm numeric promedio de máximo de noches durante los próximos 365 días
availability_365 integer disponibilidad del espacio durante los próximos 365 días
last_review Date fecha de la última puntuación
review_scores_rating numeric puntuación general del espacio
review_scores_accuracy numeric puntuación sobre la realidad/descripción del espacio
review_scores_cleanliness numeric puntuación sobre la limpieza del espacio
review_scores_checkin numeric puntuación sobre el checkin
review_scores_communication numeric puntuación sobre lo bien que está comunicado el espacio
review_scores_location numeric puntuación de la localización del espacio
review_scores_value numeric puntuación del valor del espacio
reviews_per_month numeric media de número de reviews por espacio durante un mes


Aunque se intuye antes de comenzar que hay variables que van a aportar poca información o son similares a otras o combinaciones de varias, de momento se conservarán cara a realizar un análisis previo para justificar su inclusión o exclusión de nuestro estudio.


Separación del conjunto de datos en dos grupos

Se procede a dividir el conjunto de datos en dos partes: el 70% para grupo de Training y 30% para grupo de Test. No se considera necesario un muestreo estratificado debido a que el número de observaciones es grande. Se hará de manera pseudoaleatoria:

set.seed(12345)
inTraining <- createDataPartition(pull(RawData, neighbourhood_group_cleansed),
                                  p = .7, list = FALSE, times = 1)
data_train <- slice(data, inTraining)
data_test <- slice(data, -inTraining)

groups <- data.frame("Grupos" = c("Training","Test"), "Observaciones" = c(nrow(data_train),nrow(data_test)), "Porcentaje" = c(round(nrow(data_train)*100/nrow(data),1),round(nrow(data_test)*100/nrow(data),1)))

kable(groups) %>% kable_styling("striped")
Grupos Observaciones Porcentaje
Training 13240 70
Test 5661 30


A partir de ahora, y hasta que se ponga a prueba el modelo, se utilizarán exclusivamente los datos del grupo de Training.



Análisis exploratorio univariante


Variable objetivo: price

La variable \(price\), la cual queremos predecir, en general se concentra entre los 37 y los 105€, y en general el número de Airbnbs decrece con el precio:

price <- ggplot(data_train, aes(x=price, y=..density..)) + geom_histogram(binwidth = 10, fill='cadetblue4') + geom_density(alpha = .1, fill="white") + xlim(c(0,500))

log_price <- ggplot(data_train, aes(x=log(price), y=..density..)) + geom_histogram(binwidth = 10, color='white', fill='cadetblue4') + geom_density(alpha = .1, color="#FFA500", fill="white") + xlim(c(0,10)) + ggtitle('Transformación logarítmica')

boxplot_price <- ggplot(data_train, aes(y=price)) + geom_boxplot(color="#FFA500", fill='cadetblue4') + scale_y_continuous(trans = 'log10')

quantile_price <- data.frame(quantile(data_train$price))

colnames(quantile_price) <- c("Observaciones")

tbl <- tableGrob(quantile_price)

grid.arrange(price, log_price,boxplot_price,tbl, ncol=2, nrow =2, as.table=TRUE)

El precio medio por noche es de 129.63 €. El precio mínimo es 8€, y el precio máximo es de 9999€. Se ha comprobado accediendo a la plataforma que valores tan altos no tienen por qué ser erróneos. Sin embargo, se observa que la distribución posee una cola muy larga en su lado derecho, lo cual puede dar problemas a la hora de realizar la regresión.


Variables: latitude y longitude

Los datos de latitud y longitud nos permiten conocer la localización de cada espacio alquilable. A continuación, imprimimos cada airbnb como un punto sobre un plano básico de distritos de Madrid:


spdf <- geojson_read("./02_Resources/madrid-districts.geojson",  what = "sp")
spdf_fortified <- tidy(spdf)
spdf_df <- as.data.frame(spdf)
sorted_spdf_df <- spdf_df %>% arrange(name)

#Añadimos datos de población al geojson file
sorted_spdf_df$Poblacion_2017 = c(155660, 50010, 260196, 140473, 147551, 140866, 219867, 249973, 193264, 242139, 121683, 95614, 240867, 120406, 147854, 161222, 161313, 142894, 74048, 114512, 154318)

# Gráfico de airbnbs localizadas por latitud y longitud
location <- ggplot(data_train, aes(x=longitude, y=latitude)) + geom_polygon(data = spdf_fortified, aes( x = long, y = lat, group = group), fill="grey", color="white", alpha = 0.4) + theme_void() + coord_map() + geom_point(alpha = 0.05, colour="#B03060") + ggtitle('Airbnbs Madrid') + geom_polygon(data = spdf_fortified, aes( x = long, y = lat, group = group), fill= NA, color="white", alpha = 0.1)
location

Se aprecia una clara concentración de observaciones en los distritos centrales de Madrid.


Variable: neighbourhood_group_cleansed

El estudio de esta variable es clave para cuantificar la densidad de airbnbs por distrito vista en el mapa del apartado anterior:

data_train %>%
  group_by(neighbourhood_group_cleansed) %>%
  summarise(count=n()) %>%
  ggplot(aes(x=reorder(neighbourhood_group_cleansed,(count)), y=count, fill = neighbourhood_group_cleansed)) + geom_bar(stat='identity', color = '#262626') + coord_flip() + theme(legend.position = 'none') + ggtitle('Cantidad de Airbnbs por distrito') + ylab('Observaciones') + xlab('Distritos')

#other_districts <- cuentaDistritos %>% slice(-c(1))
#centro_district <- cuentaDistritos %>% slice(c(1))

Se comprueba que la densidad de observaciones en el distrito Centro de Madrid es sumamente desproporcionada en comparación con el resto. Solo en este distrito se acumulan un 44.51% de los espacios alquilables de Madrid (casi la mitad).


Variables: room type, accomodates, bedrooms y beds

data_train %>%
  group_by(room_type) %>%
  summarise(count=n()) %>%
  ggplot(aes(x=reorder(room_type,(-count)), y=count, alpha = room_type)) + geom_bar(stat='identity', col= 'black', fill='#00868B') +
  theme(axis.text.x = element_text(size=8)) + theme(legend.position = "none") + xlab('room_type')

cuentaTipos <- data_train %>%
  group_by(room_type) %>%
  summarise(count = n()) %>%
  arrange(-count)

# Tamaño de tablas para el grid
mytheme <- gridExtra::ttheme_default(
    core = list(fg_params=list(cex = 0.5)),
    colhead = list(fg_params=list(cex = 0.5)),
    rowhead = list(fg_params=list(cex = 0.5)))

# Tabla de room types
tbl_types <- gridExtra::tableGrob(cuentaTipos, theme = mytheme)

# Accomodates
ggplot(data_train, aes(x=accommodates)) + geom_histogram(stat='count', col= 'black', fill="palegreen4") +
  theme(axis.text.x = element_text(size=8)) + theme(legend.position = "none")

cuentaAccommodates <- data_train %>%
  group_by(accommodates) %>%
  summarise(count = n()) %>%
  arrange(-count)

tbl_accom <- gridExtra::tableGrob(cuentaAccommodates, theme = mytheme)

# Bedrooms
bedrooms <- ggplot(data_train, aes(x=bedrooms)) + geom_histogram(stat='count', col= 'black', fill="orange3") +
  theme(axis.text.x = element_text(size=8)) + theme(legend.position = "none") + ylim(c(0,9000))

cuentaBedrooms <- data_train %>%
  group_by(bedrooms) %>%
  summarise(count = n()) %>%
  arrange(-count)

tbl_bedroom <- gridExtra::tableGrob(cuentaBedrooms, theme = mytheme)

# Beds
beds <- ggplot(data_train, aes(x=beds, fill =beds, alpha = beds)) + geom_histogram(stat='count', col= 'black', fill ='#8B0000') +
  theme(axis.text.x = element_text(size=8)) + theme(legend.position = "none")  + ylim(c(0,9000))

cuentaBeds <- data_train %>%
  group_by(beds) %>%
  summarise(count = n()) %>%
  arrange(-count)

tbl_bed <- gridExtra::tableGrob(cuentaBeds, theme = mytheme)

# Agrupación de tablas
grid.arrange(bedrooms, beds, ncol=2, nrow =1)

#grid.arrange(tbl_types, tbl_accom, tbl_bed, tbl_bedroom, ncol=4, nrow =1, as.table=TRUE)

Tras el análisis de las variables, agrupadas por similitud, concluímos que:

  • Aproximadamente un tercio de las propiedades son para 2 personas, y la gran mayoría son para 6 o menos.
  • Dos tercios de las propiedades tienen 1 dormitorio. La mayoría tiene 5 o menos.
  • La mayoría de las propiedades tienen entre 1 y 4 camas.
  • Existen 678 propiedades sin cama a pesar de que no existen propiedades sin dormitorios.


Variables: min_nights, max_nights, availability_365

# Min nights
min_nights <- ggplot(data_train, aes(x=minimum_nights)) + geom_histogram(bindwidth = 5, fill="violetred3", col='white')  + scale_y_continuous(trans='log10') + scale_x_continuous(limits = c(0, 400)) + theme(legend.position = "none")

cuentaMinNights <- data_train %>%
  group_by(minimum_nights) %>%
  summarise(count = n()) %>%
  arrange(-count)

tbl_min <- tableGrob(head(cuentaMinNights,10), theme = mytheme)

# Min nights average 360 days
min_night_avg <- ggplot(data_train, aes(x=minimum_nights_avg_ntm)) + geom_histogram(bindwidth = 5, fill="#CD853F", col='white')  + scale_y_continuous(trans='log10') + scale_x_continuous(limits = c(0, 400)) + theme(legend.position = "none")

cuentaMinNightsAvg <- data_train %>%
  group_by(minimum_nights_avg_ntm) %>%
  summarise(count = n()) %>%
  arrange(-count)

tbl_min_avg <- gridExtra::tableGrob(head(cuentaMinNightsAvg,10), theme = mytheme)

# Max nights average 360 days
max_night_avg <- ggplot(data_train, aes(x=maximum_nights_avg_ntm)) + geom_histogram(bindwidth = 5, fill="#40E0D0", col='white')  + scale_y_continuous(trans='log10') + xlim(c(0,2000))  + scale_x_continuous(limits = c(0, 400)) + theme(legend.position = "none")

cuentaMaxNightsAvg <- data_train %>%
  group_by(maximum_nights_avg_ntm) %>%
  summarise(count = n()) %>%
  arrange(-count)

tbl_max_avg <- gridExtra::tableGrob(head(cuentaMaxNightsAvg,10), theme = mytheme)

# availability_365
avail_360 <- ggplot(data_train, aes(x=availability_365)) + geom_histogram(bindwidth = 5, fill = 'orangered3', col='white')
#sum(data_train$availability_365==0)

# Agrupación de tablas
grid.arrange(min_nights, min_night_avg, max_night_avg, avail_360, ncol=2, nrow =2)

#grid.arrange(tbl_min, tbl_min_avg, tbl_max_avg, ncol=3, nrow =1, as.table=TRUE)

Se aprecia una gran similaridad entre las variables \(minimum\_nights\) y \(minimum\_nights\_avg\_ntm\). Proseguiremos nuestro análisis con la segunda por tratarse de la media anual, según la definición del diccionario de la base de datos, y descartaremos la primera.

La variable \(availability\_365\) muestra que hay alta disponibilidad en los siguientes casos:

  • Un 26.8% de los espacios están disponibles en los 10 días posteriores a la fecha de recogida de datos.

  • A 90 y 180 días desde la fecha de recolección de los datos. Estas fechas se corresponden con la semana posterior al “Puente de la Constitución” y la semana posterior a los carnavales.

  • La mínima disponibilidad se encuentra entre los días 200 y 220, que se corresponden con la Semana Santa.

  • Entre los 320 y los 350 días, que se corresponden con el mes de Agosto.

  • A los 360 días, que se corresponde con el inicio del mes de Septiembre.

Dado que nuestros datos no contienen la evolución temporal de los precios, la variable \(availability\_365\) no aporta gran cantidad de información respecto de los mismos. Sin embargo, se podría explorar la influencia de la disponibilidad inmediata, sobre la cual se desconoce si es tan numerosa debido a la inmediatez o a la época del año en que los datos fueron recogidos.

data_train$minimum_nights <- NULL
data_train$maximum_nights_avg_ntm <- NULL
# data_train$availability_365 <- NULL


Variables: Grupo review_scores y reviews_per_month

scores <- data_train %>%
  dplyr:: select(review_scores_rating, review_scores_accuracy, review_scores_cleanliness, review_scores_checkin, review_scores_communication, review_scores_location, review_scores_value, reviews_per_month)


rs_rating <- ggplot(scores, aes(x = review_scores_rating, y=..count..)) +
  geom_histogram(binwidth = 0.5, color='black', fill = '#458B74') + xlab("Rating")+ ylab("count")
rs_accuracy <- ggplot(scores, aes(x = review_scores_accuracy, y=..count..)) +
  geom_histogram(binwidth = 0.5, color='black', fill = '#8B2323') + xlab("Accuracy")+ ylab("count")
rs_cleanliness <- ggplot(scores, aes(x = review_scores_cleanliness, y=..count..)) +
  geom_histogram(binwidth = 0.5, color='black', fill = 'dodgerblue3') + xlab("Cleanliness")+ ylab("count")
rs_checkin <- ggplot(scores, aes(x = review_scores_checkin, y=..count..)) +
  geom_histogram(binwidth = 0.5, color='black', fill = 'darkgoldenrod2') + xlab("Check in")+ ylab("count")
rs_communication <- ggplot(scores, aes(x = review_scores_communication, y=..count..)) +
  geom_histogram(binwidth = 0.5, color='black', fill = 'darkolivegreen3') + xlab("Communication")+ ylab("count")
rs_location <- ggplot(scores, aes(x = review_scores_location, y=..count..)) +
  geom_histogram(binwidth = 0.5, color='black', fill = '#CD5B45')+ xlab("Location")+ ylab("count")
rs_value <- ggplot(scores, aes(x = review_scores_value, y=..count..)) +
  geom_histogram(binwidth = 0.5, color='black', fill = '#008B8B')+ xlab("Value")+ ylab("count")
rp_month <- ggplot(scores, aes(x = reviews_per_month, y=..count..)) +
  geom_histogram(binwidth = 0.7, fill = '#CD5555') + xlab("Per month")+ ylab("count")

grid.arrange(rs_rating, rs_accuracy, rs_cleanliness, rs_checkin, rs_communication, rs_location, rs_value, rp_month, ncol=4, nrow =2)

Podemos observar que la mayoría de las reviews son positivas, con la mayor concentración de casos entre el 4 y el 5 generalmente. Todas las variables de puntuación tienen una distribución similar, excepto en el caso de \(review\_scores\_value\) y en el de \(review\_scores\_rating\) por ser el promedio de todas con la anterior. Debido a esto, consideramos que únicamente se incluirá en el modelo \(review\_scores\_rating\).

\(reviews\_per\_month\) indica que la mayoría de espacios tienen pocas o ninguna review al mes. La representamos más en detalle:

#str(scores$reviews_per_month)
#summary(scores$reviews_per_month)
rpmonth <- na.omit(scores$reviews_per_month)
#summary(rpmonth)

# Creación del layout para diagramas
layout(matrix(c(1,2),2,1, byrow=TRUE), height = c(1,8))

# Boxplot e histograma combinados
par(mar=c(0, 5.1, 1.1, 2.1))
boxplot(rpmonth , horizontal=TRUE, xaxt="n" , col="#FFC125" , frame=F)
par(mar=c(4.5, 5.1, 1.1, 2.1))
hist(rpmonth , breaks=40 , col='#8B3A62' , border=F , main="", ylab="count", xlab="Promedio de reviews/mes", xlim=c(0,8))

La mayoria de los espacios en la base de datos, obtienen entre 0 y 2 reviews por mes de media, con más de 4000 personas con una media de 0.25 reviews por mes. Este resultado tiene sentido, ya que en general gente suele pasar una o dos de semanas seguidas de vacaciones fuera de casa, y suele haber mayor concentración de turistas en ciertas épocas del año.

data_train$review_scores_accuracy <- NULL
data_train$review_scores_cleanliness <- NULL
data_train$review_scores_checkin <- NULL
data_train$review_scores_communication <- NULL
data_train$review_scores_location <- NULL
data_train$review_scores_value <- NULL


Variables: host_since, last_review

Se ha incluido la variable \(host\_since\) para comprobar si existe una correlación entre la experiencia del arrendatario y el precio del espacio. Su distribución es la siguiente:

# Host_since
ggplot(data_train, aes(x=host_since)) + geom_histogram(bins = 50, fill="darkslategray", col='white') + theme(legend.position = "none")

En nuestro caso, creemos que podríamos sacar más partido a \(host\_since\) la convertimos al número de días transcurridos hasta la recolección de los datos \(host\_exp\_days\). De esta forma obtendremos directamente la experiencia del propietario en la plataforma y podremos comprobar si la confianza que genera su antigüedad tiene efecto en el precio.

data_train$host_exp_days <- as.integer(max(data_train$host_since, na.rm = TRUE)-data_train$host_since)
data_train$host_since <- NULL
# Host_since
ggplot(data_train, aes(x=last_review)) + geom_histogram(binwidth = 7, col='darkslategray') + theme(legend.position = "none")

Este gráfico es muy interesante, puesto que se aprecian claramente dos grupos: aquellos espacios que fueron evaluados por última vez antes del comienzo del Estado de Alarma debido al Sars-CoV-2 y aquellos que lo fueron después.

state_of_alarm <- as.Date("2020-03-15")
state_of_alarm_off_open <- as.Date("2021-06-06") # desde 7 estuven abiertas fronteras
# state_of_alarm_off <- as.Date("2021-05-09")

# Plots comparativos de enero a octubre
last_review_2019 <- ggplot(data_train, aes(x=last_review)) + geom_histogram(binwidth = 1, col='darkslategray') + theme(legend.position = "none") + xlim(c(as.Date("2019-01-01"),as.Date("2019-06-01")))
last_review_2020 <- ggplot(data_train, aes(x=last_review)) + geom_histogram(binwidth = 1, col='darkslategray') + theme(legend.position = "none") + xlim(c(as.Date("2020-01-01"),as.Date("2020-06-01"))) + geom_vline(aes(xintercept = state_of_alarm), colour="red")
last_review_2021 <- ggplot(data_train, aes(x=last_review)) + geom_histogram(binwidth = 1, col='darkslategray') + theme(legend.position = "none") + xlim(c(as.Date("2021-03-01"),as.Date("2021-09-10"))) + geom_vline(aes(xintercept = state_of_alarm_off_open), colour="red")

grid.arrange(last_review_2019, last_review_2020, last_review_2021, ncol=2, nrow =2)

# Cálculo de reviews pre- y post Covid



reviewedBeforeCovid <- count(na.omit(data_train[data_train$last_review<state_of_alarm,]))
reviewedAfterCovid <- count(na.omit(data_train[data_train$last_review>=state_of_alarm,]))

rBC_pct <- round(100*reviewedBeforeCovid/(reviewedBeforeCovid+reviewedAfterCovid),1)

Resulta interesante comprobar el descenso abrupto del número de reviews que se produce el 15 de Marzo de 2020, primer día de Estado de Alarma en España, hasta el último día: el 6 de Junio de 2021. El 7 de Junio de 2021 se reabrieron las fronteras a turistas de terceros países.

Según los datos, el 61.1% de los espacios no han recibido una review hasta el día en que se recolectaron los datos (10 de Septiembre de 2021). Podría resultar interesante comparar los precios de los espacios en función de si han sido evaluados durante el confinamiento o no.

Partiendo de la variable \(last\_review\), crearemos una nueva variable: \(reviewedAlarm\).

data_train <- data_train %>%
  mutate(reviewedAlarm = case_when(last_review>=state_of_alarm & last_review <= state_of_alarm_off_open ~ 'On', last_review < state_of_alarm | last_review > state_of_alarm_off_open ~ 'Off'))
data_train$reviewedAlarm[which(is.na(data_train$reviewedAlarm))] <- "Off" # Damos los NA por Off, dado que no constan reviews
data_train$reviewedAlarm <- as.factor(data_train$reviewedAlarm)

data_train$last_review <- NULL

ggplot(data_train, aes(x=reviewedAlarm)) + geom_bar(stat='count', col= 'black', fill='darkorange3')

Vemos que la mayoría de las estimaciones recientes se han obtenido en el tiempo pre-Covíd-19 y tras la eliminación de las principales restricciones.

Variable: host_is_superhost

\(host\_is\_superhost\) es un indicador de excelencia otorgado por la plataforma al arrendatario en base a los siguientes criterios:

  • Rating medio igual o superior a 4.8 durante el último año.

  • Han conseguido más de 10 estancias en el último año o 100 noches durante las 3 últimas estancias.

  • Ratio de cancelación inferior al 1%.

  • Un ratio de respuesta igual o superior al 90%.


Creemos que esta variable también podría influir en el precio de los espacios. La proporción de superhosts es la siguiente:

# Host is super host
ggplot(na.omit(data_train), aes(x=host_is_superhost, fill =host_is_superhost, alpha = host_is_superhost)) + geom_histogram(stat='count', col= 'black', fill='darkorange3') +
  theme(axis.text.x = element_text(size=8)) + theme(legend.position = "none")

Creación otras variables nuevas

También nos interesa combinar varias variables para crear otras nuevas que puedan aportar nuevas perspectivas. Se crearán las siguientes variables:

data_train <- data_train %>%
  add_count(host_id)
colnames(data_train)[colnames(data_train) == 'n'] <- 'host_listings_count'

data_train$id <- NULL
data_train$host_id <- NULL

data_train$price_per_person <- data_train$price/data_train$accommodates

distance <- function(origen, row){
  return(as.numeric(distm(origen, cbind(row$longitude, row$latitude),
                          fun = distHaversine))
  )
}

sol <- c(-3.7035799616333795, 40.417114256598694)

data_train$dist_sol <- distance(sol, data_train)

nuevasVariables <- data.frame("Variable" = c('host_listings_count', 'price_per_person', 'dist_sol', 'host_exp_days', 'reviewedAlarm'), "Definición" = c("Número de espacios que alquila el dueño","Precio del espacio dividido por el número de plazas ofertadas", "Distancia al centro (Puerta del Sol)","Experiencia del dueño en días", "Última revisión recibida durante las restricciones COVID-19" ))

#nuevasVariables$Tipo <- sapply(data_train[,nuevasVariables$Variable],class)
#nuevasVariables <- nuevasVariables[,c(1,3,2)]


kable(nuevasVariables)%>%kable_styling("striped")
Variable Definición
host_listings_count Número de espacios que alquila el dueño
price_per_person Precio del espacio dividido por el número de plazas ofertadas
dist_sol Distancia al centro (Puerta del Sol)
host_exp_days Experiencia del dueño en días
reviewedAlarm Última revisión recibida durante las restricciones COVID-19


Estudio e imputación de valores faltantes

Una vez realizada la copia del conjunto de datos de Training, sobre la cual trabajaremos, se comprueba cuántos valores faltantes tiene cada variable:

En el caso de host_is_superhost y host_exp_days, solo tenemos 19 observaciones faltantes, por lo que se optará por reemplazar directamente:

  • NA = false para host_is_superhost

  • NA = 0 para host_exp_days



Como el resto de variables tiene una proporción considerable de datos faltantes, se buscará un método para sustituirlos conservando su distribución.

He aquí una matriz de correlación de variables con NA:

description bedrooms beds review_scores_rating reviews_per_month
description 1.0000000 0.0970786 0.0259191 0.1498052 0.1498052
bedrooms 0.0970786 1.0000000 -0.0205773 -0.0159196 -0.0159196
beds 0.0259191 -0.0205773 1.0000000 0.0948609 0.0948609
review_scores_rating 0.1498052 -0.0159196 0.0948609 1.0000000 1.0000000
reviews_per_month 0.1498052 -0.0159196 0.0948609 1.0000000 1.0000000


Para seleccionar un método de sustitución de valores faltantes, primero se analizará qué variables están altamente correlacionadas para excluírlas del proceso, puesto que pueden conducir a una situación de multicolinealidad y, en consecuencia, dificultar su modelado. Aquí se muestran, por pares, aquellas variables que presentan una correlación superior a 0.6:

## [1] "bedrooms"         "beds"             "accommodates"     "beds"            
## [5] "accommodates"     "bedrooms"         "price_per_person" "price"



Vemos que existe un nivel relativamente alto de correlación entre las variables bedrooms, accommodates y beds.


Imputación con paquete mice


Utilizaremos los métodos rf (Random Forest) y cart (Classification and Regression Trees) del paquete mice para imputar los NA. Esta elección viene dada porque los métodos de imputación predeterminados de mice implican regresión lineal. Debido a que existe una alta probabilidad de que una columna sea una combinación lineal de otra, optamos por los métodos antes mencionados.

Random Forest:
## 
##  iter imp variable
##   1   1  bedrooms  beds  review_scores_rating  reviews_per_month
##   1   2  bedrooms  beds  review_scores_rating  reviews_per_month
##   1   3  bedrooms  beds  review_scores_rating  reviews_per_month
##   1   4  bedrooms  beds  review_scores_rating  reviews_per_month
##   1   5  bedrooms  beds  review_scores_rating  reviews_per_month
##   2   1  bedrooms  beds  review_scores_rating  reviews_per_month
##   2   2  bedrooms  beds  review_scores_rating  reviews_per_month
##   2   3  bedrooms  beds  review_scores_rating  reviews_per_month
##   2   4  bedrooms  beds  review_scores_rating  reviews_per_month
##   2   5  bedrooms  beds  review_scores_rating  reviews_per_month
##   3   1  bedrooms  beds  review_scores_rating  reviews_per_month
##   3   2  bedrooms  beds  review_scores_rating  reviews_per_month
##   3   3  bedrooms  beds  review_scores_rating  reviews_per_month
##   3   4  bedrooms  beds  review_scores_rating  reviews_per_month
##   3   5  bedrooms  beds  review_scores_rating  reviews_per_month
##   4   1  bedrooms  beds  review_scores_rating  reviews_per_month
##   4   2  bedrooms  beds  review_scores_rating  reviews_per_month
##   4   3  bedrooms  beds  review_scores_rating  reviews_per_month
##   4   4  bedrooms  beds  review_scores_rating  reviews_per_month
##   4   5  bedrooms  beds  review_scores_rating  reviews_per_month
##   5   1  bedrooms  beds  review_scores_rating  reviews_per_month
##   5   2  bedrooms  beds  review_scores_rating  reviews_per_month
##   5   3  bedrooms  beds  review_scores_rating  reviews_per_month
##   5   4  bedrooms  beds  review_scores_rating  reviews_per_month
##   5   5  bedrooms  beds  review_scores_rating  reviews_per_month


Comparación de las distribuciones de los datos reemplazados con los originales:


Classification and Regression Trees:
## 
##  iter imp variable
##   1   1  bedrooms  beds  review_scores_rating  reviews_per_month
##   1   2  bedrooms  beds  review_scores_rating  reviews_per_month
##   1   3  bedrooms  beds  review_scores_rating  reviews_per_month
##   1   4  bedrooms  beds  review_scores_rating  reviews_per_month
##   1   5  bedrooms  beds  review_scores_rating  reviews_per_month
##   2   1  bedrooms  beds  review_scores_rating  reviews_per_month
##   2   2  bedrooms  beds  review_scores_rating  reviews_per_month
##   2   3  bedrooms  beds  review_scores_rating  reviews_per_month
##   2   4  bedrooms  beds  review_scores_rating  reviews_per_month
##   2   5  bedrooms  beds  review_scores_rating  reviews_per_month
##   3   1  bedrooms  beds  review_scores_rating  reviews_per_month
##   3   2  bedrooms  beds  review_scores_rating  reviews_per_month
##   3   3  bedrooms  beds  review_scores_rating  reviews_per_month
##   3   4  bedrooms  beds  review_scores_rating  reviews_per_month
##   3   5  bedrooms  beds  review_scores_rating  reviews_per_month
##   4   1  bedrooms  beds  review_scores_rating  reviews_per_month
##   4   2  bedrooms  beds  review_scores_rating  reviews_per_month
##   4   3  bedrooms  beds  review_scores_rating  reviews_per_month
##   4   4  bedrooms  beds  review_scores_rating  reviews_per_month
##   4   5  bedrooms  beds  review_scores_rating  reviews_per_month
##   5   1  bedrooms  beds  review_scores_rating  reviews_per_month
##   5   2  bedrooms  beds  review_scores_rating  reviews_per_month
##   5   3  bedrooms  beds  review_scores_rating  reviews_per_month
##   5   4  bedrooms  beds  review_scores_rating  reviews_per_month
##   5   5  bedrooms  beds  review_scores_rating  reviews_per_month


Comparación de las distribuciones de los datos reemplazados con los originales:


Podemos apreciar que los datos imputados son muy cercanos a los datos observados, pero el resultado que más se ajusta es por el método cart. Usamos este método para imputar los NA de \(data\_train\).


Vamos a comprobar si tras las imputaciones, hemos conseguido reemplazar todos los NAs de las columnas que nos interesan de data_train (bedrooms, beds, review_scores_rating y reviews_per_month):

bedrooms 0
beds 0
review_scores_rating 0
reviews_per_month 0
data_train <- data_train_del_na



Análisis exploratorio multivariante

En esta parte se analizará la relación de la variable objetivo \(price\) con el resto de variables seleccionadas.


Análisis del precio en función de la localización

# Gráfico de airbnbs localizadas por latitud y longitud, color por precio
adjusted_price <- subset(data_train, price >0 & price < 150)
price_map <- ggplot(adjusted_price, aes(x=longitude, y=latitude, color=price, alpha = 0.2)) + geom_polygon(data = spdf_fortified, aes( x = long, y = lat, group = group), fill="grey", color="white", alpha = 0.4) + theme_void() + coord_map() + geom_point() + ggtitle('Airbnbs Madrid') + geom_polygon(data = spdf_fortified, aes( x = long, y = lat, group = group), fill= NA, color="white", alpha = 0.1) + scale_colour_gradient(low = "#8B0A50", high = "#FFA500", na.value = NA)
price_map

En este gráfico se puede apreciar cómo la mayoría de espacios de precio superior se encuentran en el distrito Centro, siendo también notoria su presencia en el Barrio de Salamanca y en torno al Paseo de la Castellana.


Análisis del precio en función del número de plazas

# price vs accommodates
pricevsAcco <- data_train %>%
  group_by(accommodates) %>%
  summarise(precio = mean(price))

ggplot(pricevsAcco, aes(x=accommodates, y=precio)) + geom_col(binwidth = 10, color='white', fill='#CD6839') # CHECK: Fairly obvious

# price vs bedrooms
pricevsBR <- data_train %>%
  group_by(bedrooms) %>%
  summarise(precio = mean(price))

price_bedr <- ggplot(pricevsBR, aes(x=bedrooms, y=precio)) + geom_col(binwidth = 10, color='white', fill='#8B2252') # CHECK: accommodates are better

# price vs beds
pricevsBeds <- data_train %>%
  group_by(beds) %>%
  summarise(precio = mean(price))

price_bds <- ggplot(pricevsBeds, aes(x=beds, y=precio)) + geom_col(binwidth = 10, color='white', fill='#698B22') # CHECK: Fairly obvious. Accommodates can be better.


grid.arrange(price_bedr, price_bds, nrow =1, ncol=2)

Se comprueba que el precio sube de manera lineal aproximadamente hasta los espacios de 6 plazas. Con los dormitorios y las camas sucede algo similar, pero \(accommodates\) nos parece mejor indicativo del precio puesto que desconocemos para cuántas personas son las camas ni cuántas camas tiene cada dormitorio.

Analicemos la distribución de precios por persona

# price vs accommodates
price <- ggplot(data_train, aes(x=price_per_person, y=..density..)) + geom_histogram(binwidth = 10, fill='cadetblue4') + geom_density(alpha = .1, fill="white") + xlim(c(0,250))

log_price <- ggplot(data_train, aes(x=log(price_per_person), y=..density..)) + geom_histogram(binwidth = 10, color='white', fill='cadetblue4') + geom_density(alpha = .1, color="#FFA500", fill="white") + xlim(c(0,10)) + ggtitle('Transformación logarítmica')

boxplot_price <- ggplot(data_train, aes(y=price_per_person)) + geom_boxplot(color="#FFA500", fill='cadetblue4') + scale_y_continuous(trans = 'log10')

quantile_price <- data.frame(quantile(data_train$price_per_person))

colnames(quantile_price) <- c("Observaciones")

tbl <- tableGrob(quantile_price)

grid.arrange(price, log_price,boxplot_price,tbl, ncol=2, nrow =2, as.table=TRUE)

En el gráfico podemos ver que la mayoría de pisos se encuentran bajo los 150€ por persona. Para un cuantil de 0.955 tenemos que el precio es de 143.76€. El número de observaciones por encima de este valor es 596, un 4.5% de los datos.

Procedemos a eliminar estas observaciones y a recalcular los cuantiles:

data_train <- data_train[data_train$price_per_person<quantile(data_train$price_per_person, 0.955),]

boxplot_price <- ggplot(data_train, aes(y=price_per_person)) + geom_boxplot(color="#FFA500", fill='cadetblue4')

quantile_price <- data.frame(quantile(data_train$price_per_person))

colnames(quantile_price) <- c("Observaciones")

tbl <- tableGrob(quantile_price)

grid.arrange(boxplot_price,tbl, ncol=2, nrow =1, as.table=TRUE)

Veamos cuánto varía el valor del precio por persona por noche dependiendo del tipo de alojamiento.

ggplot(data_train, aes(x=log(price_per_person), y=..density.., fill=room_type, color=room_type)) + geom_histogram(binwidth = 10) + geom_density(alpha = .3) + xlim(c(0,6))

Aquí vemos que la distribución del precio por persona por noche para habitaciones privadas y apartamentos individuales es bastante similar y cercana a la normalidad. Esto nos permite concluir que es más lógico considerar solo las ubicaciones en habitaciones de hotel o apartamentos para construir una regresión lineal. En primer lugar, estos tipos de alojamiento son los más característicos de AirBNB para turistas y, en segundo lugar, tienen una distribución similar del precio por persona por noche.


Análisis del precio en función del tipo de habitación

# Price vs room type
price_rtyp <- ggplot(data_train, aes(x=room_type, y=price, fill= room_type)) + geom_boxplot(outlier.size=0.2, lwd=0.25, color='black') + scale_y_continuous(trans='log10') + theme(axis.text.x = element_text(size=6, angle = 45, vjust = 0.25, hjust=0.25)) + scale_fill_brewer(palette="RdYlBu") + theme(legend.position = "none")
price_rtyp

Tiene sentido que los hoteles sean más caros que los apartamentos, estos más caros que las habitaciones privadas, y estas más caras que las compartidas.

# PricePP vs room type
pricePP_rtyp <- ggplot(data_train, aes(x=room_type, y=price_per_person, fill=room_type)) + geom_boxplot(outlier.size=0.2, lwd=0.25, color='black') + scale_y_continuous(trans='log10') + theme(axis.text.x = element_text(size=6, angle = 45, vjust = 0.25, hjust=0.25)) + scale_fill_brewer(palette="PiYG") + theme(legend.position = "none")
pricePP_rtyp

Si miramos el precio por persona, la relación se mantiene pero en mucha menor medida. Solo destaca el hotel frente al resto.


Análisis del precio en función de la distancia al centro

plot_dist <- ggplot(data_train,aes(x=log(dist_sol),y=log(price))) + geom_point() + geom_smooth(method='lm')
plot_distPP <- ggplot(data_train,aes(x=log(dist_sol),y=log(price_per_person))) + geom_point() + geom_smooth(method='lm')
plot_dist_r <- ggplot(data_train,aes(x=log(dist_sol),y=log(price), color=room_type)) + geom_point() + geom_smooth(method='lm')
plot_distPP_r <- ggplot(data_train,aes(x=log(dist_sol),y=log(price_per_person), color=room_type)) + geom_point() + geom_smooth(method='lm')


grid.arrange(plot_dist,plot_distPP,plot_dist_r,plot_distPP_r, ncol=2, nrow =2, as.table=TRUE)

Se comprueba que el precio disminuye según aumenta la distancia al centro de la ciudad. También vemos una dependencia diferente para diferentes tipos de alojamiento donde los hoteles, habitaciones privadas y apartamentos tienden a reducir el precio con el aumento de la distancia, mientras que para las habitaciones compartidas es al revés. Al mismo tiempo, los hoteles tienden a reducir el precio con la distancia al centro más bruscamente que las habitaciones individuales o los apartamentos.


Análisis del precio en función del distrito

data_train %>%
  ggplot(aes(x=(reorder(neighbourhood_group_cleansed, price, FUN=median)), y=price, fill=neighbourhood_group_cleansed)) + geom_boxplot() + scale_y_continuous(trans='log10') + coord_flip() + theme(legend.position="none") + xlab("Distritos") + ylab("Precio")

En la mayoría de casos, el precio se encuentra entre 50 y 100 euros, y apenas hay fluctuación. El caso que llama la atención, es el del distrito de “San Blas - Canillejas”: se trata de un barrio alejado del centro, más allá de la M-30. Sus precios, en principio, deberían asemejarse más a los de Ciudad Lineal que a los de Moncloa u Hortaleza.

meanPriceByDistrict <- data_train %>% group_by(neighbourhood_group_cleansed) %>% summarize(mean_price = mean(price), longitude = longitude, latitude = latitude)

ggplot(meanPriceByDistrict, aes(x=longitude,y=latitude)) + geom_point(aes(colour=mean_price)) + scale_color_gradient(low = "blue", high = "red")

dataCan <- data_train[data_train$neighbourhood_group_cleansed=="San Blas - Canillejas",]

ggplot(dataCan, aes(x=room_type, y=price, fill=room_type)) + geom_boxplot() + scale_y_continuous(trans='log10') + theme(legend.position="NONE") + ggtitle("San Blas - Canillejas") + xlab("") + scale_fill_brewer(palette="RdYlBu")

Comprobamos que no hay hoteles AirBnb en este distrito, que los precios de las habitaciones privadas se encuentran ligeramente por encima de los apartamentos, y las habitaciones compartidas quintuplican el precio de cualquiera de los anteriores. Esta comparativa no tiene en cuenta el número de personas que pueden utilizar el espacio, por lo que pasamos a representar el precio de cada espacio en función de esta variable:

can <- ggplot(dataCan, aes(x=room_type, y=price_per_person, fill=room_type)) + geom_boxplot() + scale_y_continuous(trans='log10') + theme(legend.position="NONE") + ggtitle("San Blas - Canillejas") + xlab("") + scale_fill_brewer(palette="PiYG")
can

Este resultado tiene aún menos sentido.

count(dataCan %>% group_by(room_type))
## # A tibble: 3 × 2
## # Groups:   room_type [3]
##   room_type           n
##   <chr>           <int>
## 1 Entire home/apt    84
## 2 Private room      143
## 3 Shared room         3

Como hemos encontrado unas habitaciones compartidas, nos tomaremos un momento para leer sus descripciones:

dataCan[dataCan$room_type=="Shared room","description"] 
## [1] "Salón en apartamento situado en la estación de metro de Ciudad Lineal - Pueblo nuevo , a 15 minutos en trasporte público del estadio Wanda Metropolitano y a otros 15 minutos del centro de la ciudad. Muy cerca del aeropuerto. Dispone de un sofá - cama con posibilidad de hechar un colchón de matrimonio en el suelo, también se dispone del uso del cuarto de baño, la cocina y todo lo que puedan necesitar para la estancia. Desayuno incluido<br /><br /><b>The space</b><br />Cómodo salón en apartamento"
## [2] "Habitación en espacio compartido, con un cómodo sofá-cama, área muy bonita"                                                                                                                                                                                                                                                                                                                                                                                                                                         
## [3] "acojedor ,luminoso,caliento ,te va encantar cerca para llegar al areopuerto.y al centro de la ciudad y centros comerciales y parques<br /><br /><b>The space</b><br />acojedor ,espacioso y luminoso<br /><br /><b>Guest access</b><br />el salón ,comedor  y la cosina  el pasillo acojedor,limpio<br /><br /><b>Other things to note</b><br />cerca del areopuerto y autobuses y metro y cerca de parque juan carlos .el capricho,quita de los molinos  etc"

Encontramos la palabra “wanda”, que se refiere al estadio “Wanda Metropolitano”, perteneciente al club de fútbol Atlético de Madrid, que se encuentra en el límite del distrito. Es plausible que los espacios cercanos al estadio sean alquilados a forofos del Atlético por un precio muy superior al del resto del distrito. Debido a ello, se dividirán los datos del distrito en dos: aquellas observaciones en las que se menciona el estadio y aquellas en las que no.

cercaWanda <- dataCan[grep("wanda|estadio", tolower(dataCan$description)),]
lejosWanda <- anti_join(dataCan, cercaWanda)


cerca_wanda <- ggplot(cercaWanda, aes(x=room_type, y=price_per_person, fill=room_type)) + geom_boxplot() + scale_y_continuous(trans='log10') + theme(legend.position="NONE") + ggtitle("Cerca del estadio") + xlab("") + scale_fill_brewer(palette="PuOr")
lejos_wanda <- ggplot(lejosWanda, aes(x=room_type, y=price_per_person, fill=room_type)) + geom_boxplot() + scale_y_continuous(trans='log10')  + theme(legend.position="NONE") + ggtitle("Lejos del estadio") + xlab("") + scale_fill_brewer(palette="PuOr")

grid.arrange(can, cerca_wanda, lejos_wanda, nrow=3, ncol=1)

Se puede concluir que los precios de los espacios compartidos de San Blas - Canillejas cercanos al estadio son superiores a los del resto del distrito. Estos espacios conformarán un nuevo distrito, que denominaremos “Wanda Metropolitano”.


data_train$neighbourhood_group_cleansed <- as.character(data_train$neighbourhood_group_cleansed)

data_train[rownames(cercaWanda), 'neighbourhood_group_cleansed'] <- "Wanda Metropolitano"

data_train$neighbourhood_group_cleansed <- as.factor(data_train$neighbourhood_group_cleansed)


data_train$description <- NULL
ggplot(data_train, aes(x=reorder(neighbourhood_group_cleansed, price, FUN=mean), y=price, fill=neighbourhood_group_cleansed)) + geom_boxplot() + scale_y_continuous(trans='log10') + xlab("neighbourhood_group_cleansed") + coord_flip() + theme(legend.position = "NONE") 

ggplot(data_train, aes(x=reorder(neighbourhood_group_cleansed, price_per_person, FUN=mean), y=price_per_person, fill=neighbourhood_group_cleansed)) + geom_boxplot() + scale_y_continuous(trans='log10') + xlab("neighbourhood_group_cleansed") + coord_flip() + theme(legend.position = "NONE")

El precio medio por distrito queda de la siguiente manera:

meanPriceByDistrict <- data_train %>% group_by(neighbourhood_group_cleansed) %>% summarize(mean_price = mean(price), longitude = longitude, latitude = latitude)

ggplot(meanPriceByDistrict, aes(x=longitude,y=latitude)) + geom_point(aes(colour=mean_price)) + scale_color_gradient(low = "blue", high = "red")

El precio medio por persona y distrito queda de la siguiente manera:

meanPriceByDistrict <- data_train %>% group_by(neighbourhood_group_cleansed) %>% summarize(mean_price_per_person = mean(price_per_person), longitude = longitude, latitude = latitude)

ggplot(meanPriceByDistrict, aes(x=longitude,y=latitude)) + geom_point(aes(colour=mean_price_per_person)) + scale_color_gradient(low = "blue", high = "red")

Combinamos los distritos de la ciudad en 5 grupos según el precio por persona:

  • A: Wanda Metropolitano.
  • B: Chamartín, Salamanca, San Blas - Canillejas, Chamberí.
  • C: Hortaleza, Centro, Tetuán, Moncloa - Aravaca, Retiro, Fuencarral - El Pardo.
  • D: Arganzuela, Ciudad Lineal, Carabanchel, Villa de Vallecas, Barajas, Latina, Usera, Moratalaz, Vicálvaro
  • E: Puente de Vallecas, Villaverde.
data_train <- data_train %>%
  mutate(district_price_group = case_when(neighbourhood_group_cleansed == 'Wanda Metropolitano' ~ 'A',
                                          neighbourhood_group_cleansed == 'Chamartín' | neighbourhood_group_cleansed == 'Salamanca' | neighbourhood_group_cleansed == 'San Blas - Canillejas' | neighbourhood_group_cleansed == 'Chamberí' ~ 'B',
                                          neighbourhood_group_cleansed == 'Hortaleza' | neighbourhood_group_cleansed == 'Centro' | neighbourhood_group_cleansed == 'Tetuán' | neighbourhood_group_cleansed == 'Moncloa - Aravaca' | neighbourhood_group_cleansed == 'Retiro' | neighbourhood_group_cleansed == 'Fuencarral - El Pardo' ~ 'C',
                                          neighbourhood_group_cleansed == 'Arganzuela' | neighbourhood_group_cleansed == 'Ciudad Lineal' | neighbourhood_group_cleansed == 'Carabanchel' | neighbourhood_group_cleansed == 'Villa de Vallecas' | neighbourhood_group_cleansed == 'Barajas' | neighbourhood_group_cleansed == 'Latina' | neighbourhood_group_cleansed == 'Usera' | neighbourhood_group_cleansed == 'Moratalaz' | neighbourhood_group_cleansed == 'Vicálvaro' ~ 'D', 
                                          neighbourhood_group_cleansed == 'Puente de Vallecas' | neighbourhood_group_cleansed == 'Villaverde' ~ 'E'))

data_train$district_price_group <- as.factor(data_train$district_price_group)

Los precios promedio por noche por persona quedan distribuídos de la siguiente manera:

data_train %>% 
  group_by(district_price_group) %>% 
  summarize(mean_price_per_person = mean(price_per_person)) %>% 
  arrange(desc(mean_price_per_person))
## # A tibble: 5 × 2
##   district_price_group mean_price_per_person
##   <fct>                                <dbl>
## 1 A                                     39.9
## 2 B                                     31.8
## 3 C                                     28.2
## 4 D                                     24.1
## 5 E                                     19.4


Análisis del precio en función de la experiencia del host

#Comparativa ratings con host
ggplot(data_train, aes(x = review_scores_rating, y=..count.., fill = host_is_superhost)) + geom_histogram(binwidth = 0.75, color='black', position='dodge', alpha = 1) + theme(legend.key.size = unit(0.3, 'cm'), legend.title = element_text(size = 6), legend.text = element_text(size = 6))+ xlab("Ratings")+ ylab("count")

Vemos que se cumple la definición de superhost, teniendo la mayoría de ellos un rating entre 4.5 y 5.

# price vs host_is_superhost
price_hisph <- ggplot(data_train, aes(x=host_is_superhost, y=price)) + geom_boxplot(outlier.size=0.2, lwd=0.25, color='black', fill='#FFA500') + scale_y_continuous(trans='log10') #CHECK: bit of an edge #FFA500

price_hisph

En principio no vemos diferencias en los precios según la experiencia del host, ni tampoco se aprecia una diferencia sensible dependiendo de si es superhost o no.



Análisis del precio en función de las reviews

# reviews_per_month vs price
p <- ggplot(data_train, aes(x=reviews_per_month, y=price, color=price, size=price)) + geom_point() + theme(legend.position="none")
price_rvpm <- ggMarginal(p, type="histogram",lwd=0.2,color='white', fill = "#FFC125", xparams = list(  bins=20),  size=6)

# review_scores_rating vs price
pr <- ggplot(data_train, aes(x=review_scores_rating, y=price, color=price, size=price)) + geom_point() + theme(legend.position="none")
price_rscr <- ggMarginal(pr, type="histogram",lwd=0.2,color='white', fill = "#FFC125", xparams = list(  bins=20),  size=6)

# grids
grid.arrange(price_rscr, price_rvpm, nrow =1, ncol=2)

Se observa que en general los espacios con más reviews son los que tienen un precio más alto, y que un mayor rating también podría influír en el precio.


Análisis del precio según fecha de última review

Como se mencionó en el análisis univariante, cabe la posibilidad de que haya diferencia entre precios durante las restricciones de COVID-19 y sin ellos:

ggplot(data_train, aes(x=reviewedAlarm, y = price_per_person, fill = reviewedAlarm)) + geom_boxplot() + scale_y_continuous(trans='log10') + scale_fill_brewer(palette="RdYlGn")

La diferencia de precios por persona en promedio dependiendo de si el espacio tuvo una review mientras había restricciones COVID-19 o no es de 2.68€. Queremos señalar que si no limitamos el precio máximo por persona y noche a 143 euros, esta diferencia es varias veces mayor. Esto se debe a que las ofertas más caras eran propias de la época de apogeo del turismo, antes de las restricciones.


Análisis del precio según disponibilidad y estancia mínima promedio

# price vs minimum_nights_avg_ntm
pricevsminimum_nights_avg_ntm <- data_train %>%
  group_by(minimum_nights_avg_ntm) %>%
  summarise(precio = mean(price))

price_minavgn <- ggplot(pricevsminimum_nights_avg_ntm, aes(x=log(minimum_nights_avg_ntm), y=precio)) + geom_col(fill='#FFB90F') + scale_y_continuous(trans='log10') #¿?


# price vs availability_365
pricevsavailability_365 <- data_train %>%
  group_by(availability_365) %>%
  summarise(precio = mean(price))

price_ava365 <- ggplot(pricevsavailability_365, aes(x=availability_365, y=precio)) + geom_col(fill='#8B1A1A') # CHECK: can seasonality be borrowed from here and scraping date?
grid.arrange(price_minavgn, price_ava365, nrow =1, ncol=2)

Da la impresión de que estas variables apenas se relacionan con el precio.



Análisis del precio según rating y distrito

Creamos nuevas variables: \(mean\_ratings\) y \(mean\_price\) , que representan la media de cada una de estas variables por distrito. Además, añadimos una variable más que no se encuentra en la tabla de datos original: el número de habitantes por distrito en 2017, por pura curiosidad.

price_dist_rating <- data_train %>% #na.omit(data_train) %>%
  dplyr::select(review_scores_rating, price, neighbourhood_group_cleansed)

price_dist_rating <- price_dist_rating %>%
  group_by(neighbourhood_group_cleansed) %>%
  summarise (mean_rating = mean(review_scores_rating), mean_price = mean(price))

price_dist_rating <- data.frame(price_dist_rating[price_dist_rating$neighbourhood_group_cleansed!="Wanda Metropolitano",])

head(price_dist_rating, 10)
##    neighbourhood_group_cleansed mean_rating mean_price
## 1                    Arganzuela    4.574610   64.79973
## 2                       Barajas    4.657849   61.58065
## 3                   Carabanchel    4.336600   54.06000
## 4                        Centro    4.558402   91.24012
## 5                     Chamartín    4.439682   83.47745
## 6                      Chamberí    4.437464   88.11573
## 7                 Ciudad Lineal    4.547048   60.30789
## 8         Fuencarral - El Pardo    4.477688   79.53226
## 9                     Hortaleza    4.556293   74.84914
## 10                       Latina    4.354780   49.26648
# Añadimos población del 2017 por distrito
price_dist_rating$Poblacion_2017 = c(155660, 50010, 260196, 140473, 147551, 140866, 219867, 249973, 193264, 242139, 121683, 95614, 240867, 120406, 147854, 161222, 161313, 142894, 74048, 114512, 154318)
pdr_mat <- data.frame(price_dist_rating, row.names = 1)


# Matrix format
mat <- pdr_mat
matriz <- as.matrix(mat)
heatmap(matriz, Colv = NA, Rowv = NA, scale="column", main=NA, cellnote=ifelse(matriz==0, NA, matriz), notecex=0.7,na.color=par("bg"), cexCol=0.7, col= colorRampPalette(brewer.pal(10, "YlOrRd"))(10))
legend(x="bottomright", legend=c("min", "avg", "max"), 
     fill=colorRampPalette(brewer.pal(10, "YlOrRd"))(3))

# Heatmap
#d3heatmap(mat, scale="column", dendrogram = "none", width="800px", height="80Opx", colors = "Blues")

#heatmap(matriz, Colv = NA, Rowv = NA, scale="column")
data_train$neighbourhood_group_cleansed <- NULL

El objetivo de este gráfico era realizar un análisis multivariante a tres bandas, cogiendo la variable objetivo y dos de las variables que más nos interesan. Preliminarmente, esperábamos poder ver una clara relación entre estas variables, pero a nivel visual no hay nada demasiado evidente. Algo que llama ligeramente la atención es la cierta “simetría” que parece haber entre las columnas de las reviews y la de la población, dónde hay una serie de tonos más oscuros hacia el centro de las columnas.

Es interesante ver también como las medias de reviews más altas se encuentran en barrios como Vicálvaro, Moratalaz, Moncloa, Ciudad Lineal, Fuencarral… y sin embargo zonas más pobladas de AirBnbs, como el Centro o Salamanca, parecen tener reviews más bajas.

También se puede apreciar muy ligeramente que las zonas dónde hay más población, tienen quizás una menor media de precio, intuyendo que quizás haya menos cantidad de Airbnbs porque hay más población “autóctona”.

Si aplicamos estos indicadores a los grupos de distritos creados anteriormente queda:

price_dist_rating <- data_train %>% #na.omit(data_train) %>%
  dplyr::select(review_scores_rating, price, district_price_group, price_per_person)

price_dist_rating <- price_dist_rating %>%
  group_by(district_price_group) %>%
  summarise (mean_rating = mean(review_scores_rating), mean_price = mean(price), mean_price_per_person = mean(price_per_person))

#price_dist_rating <- data.frame(price_dist_rating[price_dist_rating$district_price_group!="A",])

price_dist_rating
## # A tibble: 5 × 4
##   district_price_group mean_rating mean_price mean_price_per_person
##   <fct>                      <dbl>      <dbl>                 <dbl>
## 1 A                           4.39      132.                   39.9
## 2 B                           4.45       93.9                  31.8
## 3 C                           4.55       88.3                  28.2
## 4 D                           4.47       58.2                  24.1
## 5 E                           4.38       44.7                  19.4
# Añadimos población del 2017 por distrito
#price_dist_rating$Poblacion_2017 = c(155660, 50010, 260196, 140473, 147551, 140866, 219867, 249973, 193264, 242139, 121683, 95614, 240867, 120406, 147854, 161222, 161313, 142894, 74048, 114512, 154318)
pdr_mat <- data.frame(price_dist_rating, row.names = 1)

#write.table(heatmap_df, file = "dataforheatmap.csv",
#            sep = "\t", row.names = F)


# Matrix format
mat <- pdr_mat
matriz <- as.matrix(mat)
heatmap(matriz, Colv = NA, Rowv = NA, scale="column", main=NA,cellnote=ifelse(matriz==0, NA, matriz), notecex=0.7,na.color=par("bg"), cexCol=0.7, col= colorRampPalette(brewer.pal(10, "YlOrRd"))(10))
legend(x="bottomright", legend=c("min", "avg", "max"), 
     fill=colorRampPalette(brewer.pal(10, "YlOrRd"))(3))

# Heatmap
#d3heatmap(mat, scale="column", dendrogram = "none", width="800px", height="80Opx", colors = "Blues")

#heatmap(matriz, Colv = NA, Rowv = NA, scale="column")

Se aprecia que, en la mayoría de grupos, a ratings bajos les corresponden precios altos, y a precios bajos ratings altos.



Según lo visto hasta ahora, consideramos que las variables que tienen mayor impacto en el precio final son accommodates, dist_sol, room_type y district_price_group.



Transformaciones y procesado de variables

Aquí tenemos el resumen de los datos finales sobre los cuales construiremos nuestro modelo:

##  host_is_superhost    latitude       longitude       room_type        
##  Mode :logical     Min.   :40.33   Min.   :-3.892   Length:12644      
##  FALSE:10212       1st Qu.:40.41   1st Qu.:-3.708   Class :character  
##  TRUE :2432        Median :40.42   Median :-3.701   Mode  :character  
##                    Mean   :40.42   Mean   :-3.695                     
##                    3rd Qu.:40.43   3rd Qu.:-3.687                     
##                    Max.   :40.57   Max.   :-3.552                     
##   accommodates       bedrooms           beds           price        
##  Min.   : 1.000   Min.   : 1.000   Min.   : 0.00   Min.   :   8.00  
##  1st Qu.: 2.000   1st Qu.: 1.000   1st Qu.: 1.00   1st Qu.:  35.00  
##  Median : 2.000   Median : 1.000   Median : 1.00   Median :  61.00  
##  Mean   : 3.111   Mean   : 1.422   Mean   : 1.91   Mean   :  82.06  
##  3rd Qu.: 4.000   3rd Qu.: 2.000   3rd Qu.: 2.00   3rd Qu.:  99.00  
##  Max.   :16.000   Max.   :18.000   Max.   :18.00   Max.   :1263.00  
##  minimum_nights_avg_ntm availability_365 review_scores_rating reviews_per_month
##  Min.   :   1.000       Min.   :  0      Min.   :0.000        Min.   : 0.010   
##  1st Qu.:   1.000       1st Qu.:  0      1st Qu.:4.490        1st Qu.: 0.170   
##  Median :   2.000       Median :113      Median :4.750        Median : 0.610   
##  Mean   :   8.344       Mean   :153      Mean   :4.511        Mean   : 1.156   
##  3rd Qu.:   4.000       3rd Qu.:307      3rd Qu.:4.950        3rd Qu.: 1.640   
##  Max.   :1125.000       Max.   :365      Max.   :5.000        Max.   :12.190   
##  host_exp_days  reviewedAlarm host_listings_count price_per_person
##  Min.   :   0   Off:11547     Min.   :  1.000     Min.   :  1.50  
##  1st Qu.:1009   On : 1097     1st Qu.:  1.000     1st Qu.: 16.50  
##  Median :1802                 Median :  2.000     Median : 22.50  
##  Mean   :1779                 Mean   :  7.821     Mean   : 27.74  
##  3rd Qu.:2428                 3rd Qu.:  5.000     3rd Qu.: 32.50  
##  Max.   :4589                 Max.   :131.000     Max.   :143.75  
##     dist_sol        district_price_group
##  Min.   :   11.84   A:  82              
##  1st Qu.:  768.17   B:2162              
##  Median : 1630.54   C:7489              
##  Mean   : 2559.47   D:2420              
##  3rd Qu.: 3726.61   E: 491              
##  Max.   :23366.17
## Box-Cox Transformation
## 
## 12644 data points used to estimate Lambda
## 
## Input data summary:
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##    8.00   35.00   61.00   82.06   99.00 1263.00 
## 
## Largest/Smallest: 158 
## Sample Skewness: 4.11 
## 
## Estimated Lambda: -0.1 
## With fudge factor, Lambda = 0 will be used for transformations

Los resultados del uso de la transformación Box-Cox nos indican que la mejor transformación para la variable \(price\) sería la transformación logarítmica (Lambda = 0).

Sobre de la estadística descriptiva, quedó claro que las variables cuantitativas tienen diferentes dimensiones, lo que requiere su estandarización usando el método Box-Cox.

Nuestros datos cuantitativos ahora están estandarizados.

##     latitude        longitude       accommodates       bedrooms     
##  Min.   :0.4997   Min.   :-3.892   Min.   :0.0000   Min.   :0.0000  
##  1st Qu.:0.4997   1st Qu.:-3.708   1st Qu.:0.6931   1st Qu.:0.0000  
##  Median :0.4997   Median :-3.701   Median :0.6931   Median :0.0000  
##  Mean   :0.4997   Mean   :-3.695   Mean   :0.9541   Mean   :0.1154  
##  3rd Qu.:0.4997   3rd Qu.:-3.687   3rd Qu.:1.3863   3rd Qu.:0.3750  
##  Max.   :0.4997   Max.   :-3.552   Max.   :2.7726   Max.   :0.4985  
##  minimum_nights_avg_ntm availability_365 review_scores_rating reviews_per_month
##  Min.   :0.0000         Min.   :  0      Min.   :0.000        Min.   :-4.6052  
##  1st Qu.:0.0000         1st Qu.:  0      1st Qu.:4.490        1st Qu.:-1.7720  
##  Median :0.5671         Median :113      Median :4.750        Median :-0.4943  
##  Mean   :0.6137         Mean   :153      Mean   :4.511        Mean   :-0.6953  
##  3rd Qu.:0.9412         3rd Qu.:307      3rd Qu.:4.950        3rd Qu.: 0.4947  
##  Max.   :1.6421         Max.   :365      Max.   :5.000        Max.   : 2.5006  
##  host_exp_days       beds       host_listings_count    dist_sol     
##  Min.   :   0   Min.   : 0.00   Min.   :0.0000      Min.   : 2.472  
##  1st Qu.:1009   1st Qu.: 1.00   1st Qu.:0.0000      1st Qu.: 6.644  
##  Median :1802   Median : 1.00   Median :0.5671      Median : 7.397  
##  Mean   :1779   Mean   : 1.91   Mean   :0.5185      Mean   : 7.395  
##  3rd Qu.:2428   3rd Qu.: 2.00   3rd Qu.:1.0321      3rd Qu.: 8.223  
##  Max.   :4589   Max.   :18.00   Max.   :1.5772      Max.   :10.059

Ya que hemos definido previamente que la distribución del precio por persona por noche para habitaciones privadas y apartamentos individuales es bastante similar y cercana a la normalidad, lo más lógico para construir una regresión lineal es considerar solo los espacios en habitaciones de hotel o apartamentos completos. Por lo tanto, eliminaremos las observaciones del resto de tipos de alojamento.

A su vez, tener datos atípicos para la variable price_per_person no nos dará la oportunidad de construir una regresión lineal. Las datos atípicos serían aquellas observaciones que se desvían de 1 o 3 cuartil más de 1,5 * IQR (intercuartil escala). Por tanto, eliminaremos estas observaciones.



Aplicación de técnicas automáticas de selección de variables


Best subsets

El primer método que hemos utilizado para la regresión usando técnicas automáticas, es el de “best subset”. El resumen de todos los modelos examinados se muestra a continuación:

## Subset selection object
## Call: regsubsets.formula(log(price) ~ accommodates * district_price_group + 
##     minimum_nights_avg_ntm * district_price_group + host_is_superhost * 
##     district_price_group + host_exp_days * district_price_group + 
##     review_scores_rating * district_price_group + reviewedAlarm * 
##     district_price_group + dist_sol * district_price_group + 
##     reviews_per_month * district_price_group, data_train_sel)
## 44 Variables  (and intercept)
##                                              Forced in Forced out
## accommodates                                     FALSE      FALSE
## district_price_groupB                            FALSE      FALSE
## district_price_groupC                            FALSE      FALSE
## district_price_groupD                            FALSE      FALSE
## district_price_groupE                            FALSE      FALSE
## minimum_nights_avg_ntm                           FALSE      FALSE
## host_is_superhostTRUE                            FALSE      FALSE
## host_exp_days                                    FALSE      FALSE
## review_scores_rating                             FALSE      FALSE
## reviewedAlarmOn                                  FALSE      FALSE
## dist_sol                                         FALSE      FALSE
## reviews_per_month                                FALSE      FALSE
## accommodates:district_price_groupB               FALSE      FALSE
## accommodates:district_price_groupC               FALSE      FALSE
## accommodates:district_price_groupD               FALSE      FALSE
## accommodates:district_price_groupE               FALSE      FALSE
## district_price_groupB:minimum_nights_avg_ntm     FALSE      FALSE
## district_price_groupC:minimum_nights_avg_ntm     FALSE      FALSE
## district_price_groupD:minimum_nights_avg_ntm     FALSE      FALSE
## district_price_groupE:minimum_nights_avg_ntm     FALSE      FALSE
## district_price_groupB:host_is_superhostTRUE      FALSE      FALSE
## district_price_groupC:host_is_superhostTRUE      FALSE      FALSE
## district_price_groupD:host_is_superhostTRUE      FALSE      FALSE
## district_price_groupE:host_is_superhostTRUE      FALSE      FALSE
## district_price_groupB:host_exp_days              FALSE      FALSE
## district_price_groupC:host_exp_days              FALSE      FALSE
## district_price_groupD:host_exp_days              FALSE      FALSE
## district_price_groupE:host_exp_days              FALSE      FALSE
## district_price_groupB:review_scores_rating       FALSE      FALSE
## district_price_groupC:review_scores_rating       FALSE      FALSE
## district_price_groupD:review_scores_rating       FALSE      FALSE
## district_price_groupE:review_scores_rating       FALSE      FALSE
## district_price_groupB:reviewedAlarmOn            FALSE      FALSE
## district_price_groupC:reviewedAlarmOn            FALSE      FALSE
## district_price_groupD:reviewedAlarmOn            FALSE      FALSE
## district_price_groupE:reviewedAlarmOn            FALSE      FALSE
## district_price_groupB:dist_sol                   FALSE      FALSE
## district_price_groupC:dist_sol                   FALSE      FALSE
## district_price_groupD:dist_sol                   FALSE      FALSE
## district_price_groupE:dist_sol                   FALSE      FALSE
## district_price_groupB:reviews_per_month          FALSE      FALSE
## district_price_groupC:reviews_per_month          FALSE      FALSE
## district_price_groupD:reviews_per_month          FALSE      FALSE
## district_price_groupE:reviews_per_month          FALSE      FALSE
## 1 subsets of each size up to 8
## Selection Algorithm: exhaustive
##          accommodates district_price_groupB district_price_groupC
## 1  ( 1 ) "*"          " "                   " "                  
## 2  ( 1 ) "*"          " "                   " "                  
## 3  ( 1 ) "*"          " "                   " "                  
## 4  ( 1 ) "*"          " "                   " "                  
## 5  ( 1 ) "*"          " "                   " "                  
## 6  ( 1 ) "*"          " "                   " "                  
## 7  ( 1 ) "*"          " "                   " "                  
## 8  ( 1 ) "*"          " "                   " "                  
##          district_price_groupD district_price_groupE minimum_nights_avg_ntm
## 1  ( 1 ) " "                   " "                   " "                   
## 2  ( 1 ) " "                   " "                   " "                   
## 3  ( 1 ) " "                   " "                   " "                   
## 4  ( 1 ) " "                   " "                   " "                   
## 5  ( 1 ) " "                   " "                   " "                   
## 6  ( 1 ) " "                   " "                   " "                   
## 7  ( 1 ) " "                   " "                   " "                   
## 8  ( 1 ) " "                   " "                   " "                   
##          host_is_superhostTRUE host_exp_days review_scores_rating
## 1  ( 1 ) " "                   " "           " "                 
## 2  ( 1 ) " "                   " "           " "                 
## 3  ( 1 ) " "                   " "           " "                 
## 4  ( 1 ) " "                   " "           " "                 
## 5  ( 1 ) " "                   " "           " "                 
## 6  ( 1 ) " "                   " "           " "                 
## 7  ( 1 ) " "                   " "           " "                 
## 8  ( 1 ) " "                   " "           " "                 
##          reviewedAlarmOn dist_sol reviews_per_month
## 1  ( 1 ) " "             " "      " "              
## 2  ( 1 ) " "             " "      " "              
## 3  ( 1 ) " "             " "      " "              
## 4  ( 1 ) " "             "*"      " "              
## 5  ( 1 ) " "             "*"      " "              
## 6  ( 1 ) " "             "*"      "*"              
## 7  ( 1 ) " "             "*"      "*"              
## 8  ( 1 ) " "             "*"      "*"              
##          accommodates:district_price_groupB accommodates:district_price_groupC
## 1  ( 1 ) " "                                " "                               
## 2  ( 1 ) " "                                " "                               
## 3  ( 1 ) " "                                " "                               
## 4  ( 1 ) " "                                " "                               
## 5  ( 1 ) " "                                " "                               
## 6  ( 1 ) " "                                " "                               
## 7  ( 1 ) " "                                " "                               
## 8  ( 1 ) " "                                " "                               
##          accommodates:district_price_groupD accommodates:district_price_groupE
## 1  ( 1 ) " "                                " "                               
## 2  ( 1 ) " "                                " "                               
## 3  ( 1 ) " "                                " "                               
## 4  ( 1 ) " "                                " "                               
## 5  ( 1 ) " "                                " "                               
## 6  ( 1 ) " "                                " "                               
## 7  ( 1 ) " "                                " "                               
## 8  ( 1 ) "*"                                " "                               
##          district_price_groupB:minimum_nights_avg_ntm
## 1  ( 1 ) " "                                         
## 2  ( 1 ) " "                                         
## 3  ( 1 ) " "                                         
## 4  ( 1 ) " "                                         
## 5  ( 1 ) " "                                         
## 6  ( 1 ) " "                                         
## 7  ( 1 ) " "                                         
## 8  ( 1 ) " "                                         
##          district_price_groupC:minimum_nights_avg_ntm
## 1  ( 1 ) " "                                         
## 2  ( 1 ) " "                                         
## 3  ( 1 ) " "                                         
## 4  ( 1 ) " "                                         
## 5  ( 1 ) " "                                         
## 6  ( 1 ) " "                                         
## 7  ( 1 ) " "                                         
## 8  ( 1 ) " "                                         
##          district_price_groupD:minimum_nights_avg_ntm
## 1  ( 1 ) " "                                         
## 2  ( 1 ) " "                                         
## 3  ( 1 ) " "                                         
## 4  ( 1 ) " "                                         
## 5  ( 1 ) " "                                         
## 6  ( 1 ) " "                                         
## 7  ( 1 ) " "                                         
## 8  ( 1 ) " "                                         
##          district_price_groupE:minimum_nights_avg_ntm
## 1  ( 1 ) " "                                         
## 2  ( 1 ) " "                                         
## 3  ( 1 ) " "                                         
## 4  ( 1 ) " "                                         
## 5  ( 1 ) " "                                         
## 6  ( 1 ) " "                                         
## 7  ( 1 ) " "                                         
## 8  ( 1 ) " "                                         
##          district_price_groupB:host_is_superhostTRUE
## 1  ( 1 ) " "                                        
## 2  ( 1 ) " "                                        
## 3  ( 1 ) " "                                        
## 4  ( 1 ) " "                                        
## 5  ( 1 ) " "                                        
## 6  ( 1 ) " "                                        
## 7  ( 1 ) " "                                        
## 8  ( 1 ) " "                                        
##          district_price_groupC:host_is_superhostTRUE
## 1  ( 1 ) " "                                        
## 2  ( 1 ) " "                                        
## 3  ( 1 ) " "                                        
## 4  ( 1 ) " "                                        
## 5  ( 1 ) "*"                                        
## 6  ( 1 ) "*"                                        
## 7  ( 1 ) "*"                                        
## 8  ( 1 ) "*"                                        
##          district_price_groupD:host_is_superhostTRUE
## 1  ( 1 ) " "                                        
## 2  ( 1 ) " "                                        
## 3  ( 1 ) " "                                        
## 4  ( 1 ) " "                                        
## 5  ( 1 ) " "                                        
## 6  ( 1 ) " "                                        
## 7  ( 1 ) " "                                        
## 8  ( 1 ) " "                                        
##          district_price_groupE:host_is_superhostTRUE
## 1  ( 1 ) " "                                        
## 2  ( 1 ) " "                                        
## 3  ( 1 ) " "                                        
## 4  ( 1 ) " "                                        
## 5  ( 1 ) " "                                        
## 6  ( 1 ) " "                                        
## 7  ( 1 ) " "                                        
## 8  ( 1 ) " "                                        
##          district_price_groupB:host_exp_days
## 1  ( 1 ) " "                                
## 2  ( 1 ) " "                                
## 3  ( 1 ) " "                                
## 4  ( 1 ) " "                                
## 5  ( 1 ) " "                                
## 6  ( 1 ) " "                                
## 7  ( 1 ) " "                                
## 8  ( 1 ) " "                                
##          district_price_groupC:host_exp_days
## 1  ( 1 ) " "                                
## 2  ( 1 ) " "                                
## 3  ( 1 ) " "                                
## 4  ( 1 ) " "                                
## 5  ( 1 ) " "                                
## 6  ( 1 ) " "                                
## 7  ( 1 ) " "                                
## 8  ( 1 ) " "                                
##          district_price_groupD:host_exp_days
## 1  ( 1 ) " "                                
## 2  ( 1 ) " "                                
## 3  ( 1 ) " "                                
## 4  ( 1 ) " "                                
## 5  ( 1 ) " "                                
## 6  ( 1 ) " "                                
## 7  ( 1 ) " "                                
## 8  ( 1 ) " "                                
##          district_price_groupE:host_exp_days
## 1  ( 1 ) " "                                
## 2  ( 1 ) " "                                
## 3  ( 1 ) " "                                
## 4  ( 1 ) " "                                
## 5  ( 1 ) " "                                
## 6  ( 1 ) " "                                
## 7  ( 1 ) " "                                
## 8  ( 1 ) " "                                
##          district_price_groupB:review_scores_rating
## 1  ( 1 ) " "                                       
## 2  ( 1 ) " "                                       
## 3  ( 1 ) " "                                       
## 4  ( 1 ) "*"                                       
## 5  ( 1 ) "*"                                       
## 6  ( 1 ) "*"                                       
## 7  ( 1 ) "*"                                       
## 8  ( 1 ) "*"                                       
##          district_price_groupC:review_scores_rating
## 1  ( 1 ) " "                                       
## 2  ( 1 ) " "                                       
## 3  ( 1 ) " "                                       
## 4  ( 1 ) " "                                       
## 5  ( 1 ) " "                                       
## 6  ( 1 ) " "                                       
## 7  ( 1 ) " "                                       
## 8  ( 1 ) "*"                                       
##          district_price_groupD:review_scores_rating
## 1  ( 1 ) " "                                       
## 2  ( 1 ) " "                                       
## 3  ( 1 ) " "                                       
## 4  ( 1 ) " "                                       
## 5  ( 1 ) " "                                       
## 6  ( 1 ) " "                                       
## 7  ( 1 ) " "                                       
## 8  ( 1 ) " "                                       
##          district_price_groupE:review_scores_rating
## 1  ( 1 ) " "                                       
## 2  ( 1 ) " "                                       
## 3  ( 1 ) " "                                       
## 4  ( 1 ) " "                                       
## 5  ( 1 ) " "                                       
## 6  ( 1 ) " "                                       
## 7  ( 1 ) " "                                       
## 8  ( 1 ) " "                                       
##          district_price_groupB:reviewedAlarmOn
## 1  ( 1 ) " "                                  
## 2  ( 1 ) " "                                  
## 3  ( 1 ) " "                                  
## 4  ( 1 ) " "                                  
## 5  ( 1 ) " "                                  
## 6  ( 1 ) " "                                  
## 7  ( 1 ) " "                                  
## 8  ( 1 ) " "                                  
##          district_price_groupC:reviewedAlarmOn
## 1  ( 1 ) " "                                  
## 2  ( 1 ) " "                                  
## 3  ( 1 ) " "                                  
## 4  ( 1 ) " "                                  
## 5  ( 1 ) " "                                  
## 6  ( 1 ) " "                                  
## 7  ( 1 ) " "                                  
## 8  ( 1 ) " "                                  
##          district_price_groupD:reviewedAlarmOn
## 1  ( 1 ) " "                                  
## 2  ( 1 ) " "                                  
## 3  ( 1 ) " "                                  
## 4  ( 1 ) " "                                  
## 5  ( 1 ) " "                                  
## 6  ( 1 ) " "                                  
## 7  ( 1 ) " "                                  
## 8  ( 1 ) " "                                  
##          district_price_groupE:reviewedAlarmOn district_price_groupB:dist_sol
## 1  ( 1 ) " "                                   " "                           
## 2  ( 1 ) " "                                   " "                           
## 3  ( 1 ) " "                                   " "                           
## 4  ( 1 ) " "                                   " "                           
## 5  ( 1 ) " "                                   " "                           
## 6  ( 1 ) " "                                   " "                           
## 7  ( 1 ) " "                                   " "                           
## 8  ( 1 ) " "                                   " "                           
##          district_price_groupC:dist_sol district_price_groupD:dist_sol
## 1  ( 1 ) " "                            " "                           
## 2  ( 1 ) " "                            "*"                           
## 3  ( 1 ) " "                            "*"                           
## 4  ( 1 ) "*"                            " "                           
## 5  ( 1 ) "*"                            " "                           
## 6  ( 1 ) "*"                            " "                           
## 7  ( 1 ) " "                            "*"                           
## 8  ( 1 ) " "                            " "                           
##          district_price_groupE:dist_sol district_price_groupB:reviews_per_month
## 1  ( 1 ) " "                            " "                                    
## 2  ( 1 ) " "                            " "                                    
## 3  ( 1 ) "*"                            " "                                    
## 4  ( 1 ) " "                            " "                                    
## 5  ( 1 ) " "                            " "                                    
## 6  ( 1 ) " "                            " "                                    
## 7  ( 1 ) "*"                            " "                                    
## 8  ( 1 ) "*"                            " "                                    
##          district_price_groupC:reviews_per_month
## 1  ( 1 ) " "                                    
## 2  ( 1 ) " "                                    
## 3  ( 1 ) " "                                    
## 4  ( 1 ) " "                                    
## 5  ( 1 ) " "                                    
## 6  ( 1 ) " "                                    
## 7  ( 1 ) " "                                    
## 8  ( 1 ) " "                                    
##          district_price_groupD:reviews_per_month
## 1  ( 1 ) " "                                    
## 2  ( 1 ) " "                                    
## 3  ( 1 ) " "                                    
## 4  ( 1 ) " "                                    
## 5  ( 1 ) " "                                    
## 6  ( 1 ) " "                                    
## 7  ( 1 ) " "                                    
## 8  ( 1 ) " "                                    
##          district_price_groupE:reviews_per_month
## 1  ( 1 ) " "                                    
## 2  ( 1 ) " "                                    
## 3  ( 1 ) " "                                    
## 4  ( 1 ) " "                                    
## 5  ( 1 ) " "                                    
## 6  ( 1 ) " "                                    
## 7  ( 1 ) " "                                    
## 8  ( 1 ) " "

Para evaluar los resultados obtenidos, se ha observado:

  • El coeficiente R2 ajustado asociado a cada modelo
## [1] 0.5773847 0.5980773 0.6109850 0.6144527 0.6168325 0.6199873 0.6209073
## [8] 0.6214533
  • El criterio BIC asociado a cada modelo
## [1]  -9994.81 -10570.05 -10941.15 -11036.88 -11100.50 -11188.25 -11208.07
## [8] -11216.46
  • El criterio CP asociado a cada modelo
## [1] 1456.10366  816.73676  418.32866  312.01843  239.38075  142.78174  115.31734
## [8]   99.42323

La mejor opción es el modelo 8, con los siguientes coeficientes:

##                                 (Intercept) 
##                                  3.57632289 
##                                accommodates 
##                                  0.83188253 
##                                    dist_sol 
##                                 -0.06078741 
##                           reviews_per_month 
##                                 -0.02792398 
##          accommodates:district_price_groupD 
##                                 -0.07585221 
## district_price_groupC:host_is_superhostTRUE 
##                                  0.11972721 
##  district_price_groupB:review_scores_rating 
##                                  0.04755141 
##  district_price_groupC:review_scores_rating 
##                                  0.02406331 
##              district_price_groupE:dist_sol 
##                                 -0.01962802


Backward Selection

El último método de selección automática de variables que se ha puesto en práctica es el de Backward Selection. En este caso se parte de un modelo con todos los predictores y se van eliminando uno a uno (en cada paso se elimina la variable más significativa para el modelo):

## Subset selection object
## Call: regsubsets.formula(log(price) ~ accommodates * district_price_group + 
##     minimum_nights_avg_ntm * district_price_group + host_is_superhost * 
##     district_price_group + host_exp_days * district_price_group + 
##     review_scores_rating * district_price_group + reviewedAlarm * 
##     district_price_group + dist_sol * district_price_group + 
##     reviews_per_month * district_price_group, data_train_sel, 
##     method = "backward")
## 44 Variables  (and intercept)
##                                              Forced in Forced out
## accommodates                                     FALSE      FALSE
## district_price_groupB                            FALSE      FALSE
## district_price_groupC                            FALSE      FALSE
## district_price_groupD                            FALSE      FALSE
## district_price_groupE                            FALSE      FALSE
## minimum_nights_avg_ntm                           FALSE      FALSE
## host_is_superhostTRUE                            FALSE      FALSE
## host_exp_days                                    FALSE      FALSE
## review_scores_rating                             FALSE      FALSE
## reviewedAlarmOn                                  FALSE      FALSE
## dist_sol                                         FALSE      FALSE
## reviews_per_month                                FALSE      FALSE
## accommodates:district_price_groupB               FALSE      FALSE
## accommodates:district_price_groupC               FALSE      FALSE
## accommodates:district_price_groupD               FALSE      FALSE
## accommodates:district_price_groupE               FALSE      FALSE
## district_price_groupB:minimum_nights_avg_ntm     FALSE      FALSE
## district_price_groupC:minimum_nights_avg_ntm     FALSE      FALSE
## district_price_groupD:minimum_nights_avg_ntm     FALSE      FALSE
## district_price_groupE:minimum_nights_avg_ntm     FALSE      FALSE
## district_price_groupB:host_is_superhostTRUE      FALSE      FALSE
## district_price_groupC:host_is_superhostTRUE      FALSE      FALSE
## district_price_groupD:host_is_superhostTRUE      FALSE      FALSE
## district_price_groupE:host_is_superhostTRUE      FALSE      FALSE
## district_price_groupB:host_exp_days              FALSE      FALSE
## district_price_groupC:host_exp_days              FALSE      FALSE
## district_price_groupD:host_exp_days              FALSE      FALSE
## district_price_groupE:host_exp_days              FALSE      FALSE
## district_price_groupB:review_scores_rating       FALSE      FALSE
## district_price_groupC:review_scores_rating       FALSE      FALSE
## district_price_groupD:review_scores_rating       FALSE      FALSE
## district_price_groupE:review_scores_rating       FALSE      FALSE
## district_price_groupB:reviewedAlarmOn            FALSE      FALSE
## district_price_groupC:reviewedAlarmOn            FALSE      FALSE
## district_price_groupD:reviewedAlarmOn            FALSE      FALSE
## district_price_groupE:reviewedAlarmOn            FALSE      FALSE
## district_price_groupB:dist_sol                   FALSE      FALSE
## district_price_groupC:dist_sol                   FALSE      FALSE
## district_price_groupD:dist_sol                   FALSE      FALSE
## district_price_groupE:dist_sol                   FALSE      FALSE
## district_price_groupB:reviews_per_month          FALSE      FALSE
## district_price_groupC:reviews_per_month          FALSE      FALSE
## district_price_groupD:reviews_per_month          FALSE      FALSE
## district_price_groupE:reviews_per_month          FALSE      FALSE
## 1 subsets of each size up to 8
## Selection Algorithm: backward
##          accommodates district_price_groupB district_price_groupC
## 1  ( 1 ) "*"          " "                   " "                  
## 2  ( 1 ) "*"          " "                   "*"                  
## 3  ( 1 ) "*"          "*"                   "*"                  
## 4  ( 1 ) "*"          "*"                   "*"                  
## 5  ( 1 ) "*"          "*"                   "*"                  
## 6  ( 1 ) "*"          "*"                   "*"                  
## 7  ( 1 ) "*"          "*"                   "*"                  
## 8  ( 1 ) "*"          "*"                   "*"                  
##          district_price_groupD district_price_groupE minimum_nights_avg_ntm
## 1  ( 1 ) " "                   " "                   " "                   
## 2  ( 1 ) " "                   " "                   " "                   
## 3  ( 1 ) " "                   " "                   " "                   
## 4  ( 1 ) " "                   " "                   " "                   
## 5  ( 1 ) " "                   " "                   " "                   
## 6  ( 1 ) " "                   " "                   " "                   
## 7  ( 1 ) " "                   " "                   " "                   
## 8  ( 1 ) " "                   " "                   " "                   
##          host_is_superhostTRUE host_exp_days review_scores_rating
## 1  ( 1 ) " "                   " "           " "                 
## 2  ( 1 ) " "                   " "           " "                 
## 3  ( 1 ) " "                   " "           " "                 
## 4  ( 1 ) " "                   " "           " "                 
## 5  ( 1 ) " "                   " "           " "                 
## 6  ( 1 ) " "                   " "           " "                 
## 7  ( 1 ) " "                   " "           " "                 
## 8  ( 1 ) " "                   " "           " "                 
##          reviewedAlarmOn dist_sol reviews_per_month
## 1  ( 1 ) " "             " "      " "              
## 2  ( 1 ) " "             " "      " "              
## 3  ( 1 ) " "             " "      " "              
## 4  ( 1 ) " "             " "      " "              
## 5  ( 1 ) " "             " "      " "              
## 6  ( 1 ) " "             " "      "*"              
## 7  ( 1 ) " "             " "      "*"              
## 8  ( 1 ) " "             " "      "*"              
##          accommodates:district_price_groupB accommodates:district_price_groupC
## 1  ( 1 ) " "                                " "                               
## 2  ( 1 ) " "                                " "                               
## 3  ( 1 ) " "                                " "                               
## 4  ( 1 ) " "                                " "                               
## 5  ( 1 ) " "                                " "                               
## 6  ( 1 ) " "                                " "                               
## 7  ( 1 ) " "                                " "                               
## 8  ( 1 ) " "                                " "                               
##          accommodates:district_price_groupD accommodates:district_price_groupE
## 1  ( 1 ) " "                                " "                               
## 2  ( 1 ) " "                                " "                               
## 3  ( 1 ) " "                                " "                               
## 4  ( 1 ) " "                                " "                               
## 5  ( 1 ) " "                                " "                               
## 6  ( 1 ) " "                                " "                               
## 7  ( 1 ) " "                                " "                               
## 8  ( 1 ) " "                                " "                               
##          district_price_groupB:minimum_nights_avg_ntm
## 1  ( 1 ) " "                                         
## 2  ( 1 ) " "                                         
## 3  ( 1 ) " "                                         
## 4  ( 1 ) " "                                         
## 5  ( 1 ) " "                                         
## 6  ( 1 ) " "                                         
## 7  ( 1 ) " "                                         
## 8  ( 1 ) " "                                         
##          district_price_groupC:minimum_nights_avg_ntm
## 1  ( 1 ) " "                                         
## 2  ( 1 ) " "                                         
## 3  ( 1 ) " "                                         
## 4  ( 1 ) " "                                         
## 5  ( 1 ) " "                                         
## 6  ( 1 ) " "                                         
## 7  ( 1 ) " "                                         
## 8  ( 1 ) " "                                         
##          district_price_groupD:minimum_nights_avg_ntm
## 1  ( 1 ) " "                                         
## 2  ( 1 ) " "                                         
## 3  ( 1 ) " "                                         
## 4  ( 1 ) " "                                         
## 5  ( 1 ) " "                                         
## 6  ( 1 ) " "                                         
## 7  ( 1 ) " "                                         
## 8  ( 1 ) " "                                         
##          district_price_groupE:minimum_nights_avg_ntm
## 1  ( 1 ) " "                                         
## 2  ( 1 ) " "                                         
## 3  ( 1 ) " "                                         
## 4  ( 1 ) " "                                         
## 5  ( 1 ) " "                                         
## 6  ( 1 ) " "                                         
## 7  ( 1 ) " "                                         
## 8  ( 1 ) " "                                         
##          district_price_groupB:host_is_superhostTRUE
## 1  ( 1 ) " "                                        
## 2  ( 1 ) " "                                        
## 3  ( 1 ) " "                                        
## 4  ( 1 ) " "                                        
## 5  ( 1 ) " "                                        
## 6  ( 1 ) " "                                        
## 7  ( 1 ) " "                                        
## 8  ( 1 ) " "                                        
##          district_price_groupC:host_is_superhostTRUE
## 1  ( 1 ) " "                                        
## 2  ( 1 ) " "                                        
## 3  ( 1 ) " "                                        
## 4  ( 1 ) "*"                                        
## 5  ( 1 ) "*"                                        
## 6  ( 1 ) "*"                                        
## 7  ( 1 ) "*"                                        
## 8  ( 1 ) "*"                                        
##          district_price_groupD:host_is_superhostTRUE
## 1  ( 1 ) " "                                        
## 2  ( 1 ) " "                                        
## 3  ( 1 ) " "                                        
## 4  ( 1 ) " "                                        
## 5  ( 1 ) " "                                        
## 6  ( 1 ) " "                                        
## 7  ( 1 ) " "                                        
## 8  ( 1 ) " "                                        
##          district_price_groupE:host_is_superhostTRUE
## 1  ( 1 ) " "                                        
## 2  ( 1 ) " "                                        
## 3  ( 1 ) " "                                        
## 4  ( 1 ) " "                                        
## 5  ( 1 ) " "                                        
## 6  ( 1 ) " "                                        
## 7  ( 1 ) " "                                        
## 8  ( 1 ) " "                                        
##          district_price_groupB:host_exp_days
## 1  ( 1 ) " "                                
## 2  ( 1 ) " "                                
## 3  ( 1 ) " "                                
## 4  ( 1 ) " "                                
## 5  ( 1 ) " "                                
## 6  ( 1 ) " "                                
## 7  ( 1 ) " "                                
## 8  ( 1 ) " "                                
##          district_price_groupC:host_exp_days
## 1  ( 1 ) " "                                
## 2  ( 1 ) " "                                
## 3  ( 1 ) " "                                
## 4  ( 1 ) " "                                
## 5  ( 1 ) " "                                
## 6  ( 1 ) " "                                
## 7  ( 1 ) " "                                
## 8  ( 1 ) " "                                
##          district_price_groupD:host_exp_days
## 1  ( 1 ) " "                                
## 2  ( 1 ) " "                                
## 3  ( 1 ) " "                                
## 4  ( 1 ) " "                                
## 5  ( 1 ) " "                                
## 6  ( 1 ) " "                                
## 7  ( 1 ) " "                                
## 8  ( 1 ) " "                                
##          district_price_groupE:host_exp_days
## 1  ( 1 ) " "                                
## 2  ( 1 ) " "                                
## 3  ( 1 ) " "                                
## 4  ( 1 ) " "                                
## 5  ( 1 ) " "                                
## 6  ( 1 ) " "                                
## 7  ( 1 ) " "                                
## 8  ( 1 ) " "                                
##          district_price_groupB:review_scores_rating
## 1  ( 1 ) " "                                       
## 2  ( 1 ) " "                                       
## 3  ( 1 ) " "                                       
## 4  ( 1 ) " "                                       
## 5  ( 1 ) " "                                       
## 6  ( 1 ) " "                                       
## 7  ( 1 ) " "                                       
## 8  ( 1 ) " "                                       
##          district_price_groupC:review_scores_rating
## 1  ( 1 ) " "                                       
## 2  ( 1 ) " "                                       
## 3  ( 1 ) " "                                       
## 4  ( 1 ) " "                                       
## 5  ( 1 ) " "                                       
## 6  ( 1 ) " "                                       
## 7  ( 1 ) " "                                       
## 8  ( 1 ) " "                                       
##          district_price_groupD:review_scores_rating
## 1  ( 1 ) " "                                       
## 2  ( 1 ) " "                                       
## 3  ( 1 ) " "                                       
## 4  ( 1 ) " "                                       
## 5  ( 1 ) " "                                       
## 6  ( 1 ) " "                                       
## 7  ( 1 ) " "                                       
## 8  ( 1 ) " "                                       
##          district_price_groupE:review_scores_rating
## 1  ( 1 ) " "                                       
## 2  ( 1 ) " "                                       
## 3  ( 1 ) " "                                       
## 4  ( 1 ) " "                                       
## 5  ( 1 ) " "                                       
## 6  ( 1 ) " "                                       
## 7  ( 1 ) " "                                       
## 8  ( 1 ) " "                                       
##          district_price_groupB:reviewedAlarmOn
## 1  ( 1 ) " "                                  
## 2  ( 1 ) " "                                  
## 3  ( 1 ) " "                                  
## 4  ( 1 ) " "                                  
## 5  ( 1 ) " "                                  
## 6  ( 1 ) " "                                  
## 7  ( 1 ) " "                                  
## 8  ( 1 ) " "                                  
##          district_price_groupC:reviewedAlarmOn
## 1  ( 1 ) " "                                  
## 2  ( 1 ) " "                                  
## 3  ( 1 ) " "                                  
## 4  ( 1 ) " "                                  
## 5  ( 1 ) " "                                  
## 6  ( 1 ) " "                                  
## 7  ( 1 ) " "                                  
## 8  ( 1 ) " "                                  
##          district_price_groupD:reviewedAlarmOn
## 1  ( 1 ) " "                                  
## 2  ( 1 ) " "                                  
## 3  ( 1 ) " "                                  
## 4  ( 1 ) " "                                  
## 5  ( 1 ) " "                                  
## 6  ( 1 ) " "                                  
## 7  ( 1 ) " "                                  
## 8  ( 1 ) " "                                  
##          district_price_groupE:reviewedAlarmOn district_price_groupB:dist_sol
## 1  ( 1 ) " "                                   " "                           
## 2  ( 1 ) " "                                   " "                           
## 3  ( 1 ) " "                                   " "                           
## 4  ( 1 ) " "                                   " "                           
## 5  ( 1 ) " "                                   " "                           
## 6  ( 1 ) " "                                   " "                           
## 7  ( 1 ) " "                                   "*"                           
## 8  ( 1 ) " "                                   "*"                           
##          district_price_groupC:dist_sol district_price_groupD:dist_sol
## 1  ( 1 ) " "                            " "                           
## 2  ( 1 ) " "                            " "                           
## 3  ( 1 ) " "                            " "                           
## 4  ( 1 ) " "                            " "                           
## 5  ( 1 ) "*"                            " "                           
## 6  ( 1 ) "*"                            " "                           
## 7  ( 1 ) "*"                            " "                           
## 8  ( 1 ) "*"                            " "                           
##          district_price_groupE:dist_sol district_price_groupB:reviews_per_month
## 1  ( 1 ) " "                            " "                                    
## 2  ( 1 ) " "                            " "                                    
## 3  ( 1 ) " "                            " "                                    
## 4  ( 1 ) " "                            " "                                    
## 5  ( 1 ) " "                            " "                                    
## 6  ( 1 ) " "                            " "                                    
## 7  ( 1 ) " "                            " "                                    
## 8  ( 1 ) "*"                            " "                                    
##          district_price_groupC:reviews_per_month
## 1  ( 1 ) " "                                    
## 2  ( 1 ) " "                                    
## 3  ( 1 ) " "                                    
## 4  ( 1 ) " "                                    
## 5  ( 1 ) " "                                    
## 6  ( 1 ) " "                                    
## 7  ( 1 ) " "                                    
## 8  ( 1 ) " "                                    
##          district_price_groupD:reviews_per_month
## 1  ( 1 ) " "                                    
## 2  ( 1 ) " "                                    
## 3  ( 1 ) " "                                    
## 4  ( 1 ) " "                                    
## 5  ( 1 ) " "                                    
## 6  ( 1 ) " "                                    
## 7  ( 1 ) " "                                    
## 8  ( 1 ) " "                                    
##          district_price_groupE:reviews_per_month
## 1  ( 1 ) " "                                    
## 2  ( 1 ) " "                                    
## 3  ( 1 ) " "                                    
## 4  ( 1 ) " "                                    
## 5  ( 1 ) " "                                    
## 6  ( 1 ) " "                                    
## 7  ( 1 ) " "                                    
## 8  ( 1 ) " "

Para evaluar los resultados obtenidos, se ha observado:

  • El coeficiente R2 ajustado asociado a cada modelo
## [1] 0.5773847 0.5894066 0.6092067 0.6117610 0.6141819 0.6167879 0.6189583
## [8] 0.6201692
  • El criterio BIC asociado a cada modelo
## [1]  -9994.81 -10321.93 -10888.13 -10956.01 -11020.36 -11090.79 -11148.46
## [8] -11177.10
  • El criterio CP asociado a cada modelo
## [1] 1456.1037 1085.0139  473.3467  395.2872  321.3694  241.7375  175.5939
## [8]  139.1338

La mejor opcion es el modelo 8, con los coeficientes:

##                                 (Intercept) 
##                                  3.03533184 
##                                accommodates 
##                                  0.81663297 
##                       district_price_groupB 
##                                  1.70701732 
##                       district_price_groupC 
##                                  0.60556309 
##                           reviews_per_month 
##                                 -0.02500640 
## district_price_groupC:host_is_superhostTRUE 
##                                  0.12721494 
##              district_price_groupB:dist_sol 
##                                 -0.17852964 
##              district_price_groupC:dist_sol 
##                                 -0.05193971 
##              district_price_groupE:dist_sol 
##                                 -0.01542047


Forward Selection

Otra de las técnicas utilizadas es la de Forward Selection, en la que se parte de un modelo vacío y se van añadiendo variables. Los resultados obtenidos han sido los siguientes:

## Subset selection object
## Call: regsubsets.formula(log(price) ~ accommodates * district_price_group + 
##     minimum_nights_avg_ntm * district_price_group + host_is_superhost * 
##     district_price_group + host_exp_days * district_price_group + 
##     review_scores_rating * district_price_group + reviewedAlarm * 
##     district_price_group + dist_sol * district_price_group + 
##     reviews_per_month * district_price_group, data_train_sel, 
##     method = "forward")
## 44 Variables  (and intercept)
##                                              Forced in Forced out
## accommodates                                     FALSE      FALSE
## district_price_groupB                            FALSE      FALSE
## district_price_groupC                            FALSE      FALSE
## district_price_groupD                            FALSE      FALSE
## district_price_groupE                            FALSE      FALSE
## minimum_nights_avg_ntm                           FALSE      FALSE
## host_is_superhostTRUE                            FALSE      FALSE
## host_exp_days                                    FALSE      FALSE
## review_scores_rating                             FALSE      FALSE
## reviewedAlarmOn                                  FALSE      FALSE
## dist_sol                                         FALSE      FALSE
## reviews_per_month                                FALSE      FALSE
## accommodates:district_price_groupB               FALSE      FALSE
## accommodates:district_price_groupC               FALSE      FALSE
## accommodates:district_price_groupD               FALSE      FALSE
## accommodates:district_price_groupE               FALSE      FALSE
## district_price_groupB:minimum_nights_avg_ntm     FALSE      FALSE
## district_price_groupC:minimum_nights_avg_ntm     FALSE      FALSE
## district_price_groupD:minimum_nights_avg_ntm     FALSE      FALSE
## district_price_groupE:minimum_nights_avg_ntm     FALSE      FALSE
## district_price_groupB:host_is_superhostTRUE      FALSE      FALSE
## district_price_groupC:host_is_superhostTRUE      FALSE      FALSE
## district_price_groupD:host_is_superhostTRUE      FALSE      FALSE
## district_price_groupE:host_is_superhostTRUE      FALSE      FALSE
## district_price_groupB:host_exp_days              FALSE      FALSE
## district_price_groupC:host_exp_days              FALSE      FALSE
## district_price_groupD:host_exp_days              FALSE      FALSE
## district_price_groupE:host_exp_days              FALSE      FALSE
## district_price_groupB:review_scores_rating       FALSE      FALSE
## district_price_groupC:review_scores_rating       FALSE      FALSE
## district_price_groupD:review_scores_rating       FALSE      FALSE
## district_price_groupE:review_scores_rating       FALSE      FALSE
## district_price_groupB:reviewedAlarmOn            FALSE      FALSE
## district_price_groupC:reviewedAlarmOn            FALSE      FALSE
## district_price_groupD:reviewedAlarmOn            FALSE      FALSE
## district_price_groupE:reviewedAlarmOn            FALSE      FALSE
## district_price_groupB:dist_sol                   FALSE      FALSE
## district_price_groupC:dist_sol                   FALSE      FALSE
## district_price_groupD:dist_sol                   FALSE      FALSE
## district_price_groupE:dist_sol                   FALSE      FALSE
## district_price_groupB:reviews_per_month          FALSE      FALSE
## district_price_groupC:reviews_per_month          FALSE      FALSE
## district_price_groupD:reviews_per_month          FALSE      FALSE
## district_price_groupE:reviews_per_month          FALSE      FALSE
## 1 subsets of each size up to 8
## Selection Algorithm: forward
##          accommodates district_price_groupB district_price_groupC
## 1  ( 1 ) "*"          " "                   " "                  
## 2  ( 1 ) "*"          " "                   " "                  
## 3  ( 1 ) "*"          " "                   " "                  
## 4  ( 1 ) "*"          " "                   " "                  
## 5  ( 1 ) "*"          " "                   " "                  
## 6  ( 1 ) "*"          " "                   " "                  
## 7  ( 1 ) "*"          " "                   " "                  
## 8  ( 1 ) "*"          " "                   " "                  
##          district_price_groupD district_price_groupE minimum_nights_avg_ntm
## 1  ( 1 ) " "                   " "                   " "                   
## 2  ( 1 ) " "                   " "                   " "                   
## 3  ( 1 ) " "                   " "                   " "                   
## 4  ( 1 ) " "                   " "                   " "                   
## 5  ( 1 ) " "                   " "                   " "                   
## 6  ( 1 ) " "                   " "                   " "                   
## 7  ( 1 ) " "                   " "                   " "                   
## 8  ( 1 ) " "                   " "                   " "                   
##          host_is_superhostTRUE host_exp_days review_scores_rating
## 1  ( 1 ) " "                   " "           " "                 
## 2  ( 1 ) " "                   " "           " "                 
## 3  ( 1 ) " "                   " "           " "                 
## 4  ( 1 ) " "                   " "           " "                 
## 5  ( 1 ) " "                   " "           " "                 
## 6  ( 1 ) "*"                   " "           " "                 
## 7  ( 1 ) "*"                   " "           " "                 
## 8  ( 1 ) "*"                   " "           " "                 
##          reviewedAlarmOn dist_sol reviews_per_month
## 1  ( 1 ) " "             " "      " "              
## 2  ( 1 ) " "             " "      " "              
## 3  ( 1 ) " "             " "      " "              
## 4  ( 1 ) " "             "*"      " "              
## 5  ( 1 ) " "             "*"      "*"              
## 6  ( 1 ) " "             "*"      "*"              
## 7  ( 1 ) " "             "*"      "*"              
## 8  ( 1 ) " "             "*"      "*"              
##          accommodates:district_price_groupB accommodates:district_price_groupC
## 1  ( 1 ) " "                                " "                               
## 2  ( 1 ) " "                                " "                               
## 3  ( 1 ) " "                                " "                               
## 4  ( 1 ) " "                                " "                               
## 5  ( 1 ) " "                                " "                               
## 6  ( 1 ) " "                                " "                               
## 7  ( 1 ) " "                                " "                               
## 8  ( 1 ) " "                                " "                               
##          accommodates:district_price_groupD accommodates:district_price_groupE
## 1  ( 1 ) " "                                " "                               
## 2  ( 1 ) " "                                " "                               
## 3  ( 1 ) " "                                " "                               
## 4  ( 1 ) " "                                " "                               
## 5  ( 1 ) " "                                " "                               
## 6  ( 1 ) " "                                " "                               
## 7  ( 1 ) " "                                " "                               
## 8  ( 1 ) " "                                " "                               
##          district_price_groupB:minimum_nights_avg_ntm
## 1  ( 1 ) " "                                         
## 2  ( 1 ) " "                                         
## 3  ( 1 ) " "                                         
## 4  ( 1 ) " "                                         
## 5  ( 1 ) " "                                         
## 6  ( 1 ) " "                                         
## 7  ( 1 ) " "                                         
## 8  ( 1 ) " "                                         
##          district_price_groupC:minimum_nights_avg_ntm
## 1  ( 1 ) " "                                         
## 2  ( 1 ) " "                                         
## 3  ( 1 ) " "                                         
## 4  ( 1 ) " "                                         
## 5  ( 1 ) " "                                         
## 6  ( 1 ) " "                                         
## 7  ( 1 ) " "                                         
## 8  ( 1 ) " "                                         
##          district_price_groupD:minimum_nights_avg_ntm
## 1  ( 1 ) " "                                         
## 2  ( 1 ) " "                                         
## 3  ( 1 ) " "                                         
## 4  ( 1 ) " "                                         
## 5  ( 1 ) " "                                         
## 6  ( 1 ) " "                                         
## 7  ( 1 ) " "                                         
## 8  ( 1 ) " "                                         
##          district_price_groupE:minimum_nights_avg_ntm
## 1  ( 1 ) " "                                         
## 2  ( 1 ) " "                                         
## 3  ( 1 ) " "                                         
## 4  ( 1 ) " "                                         
## 5  ( 1 ) " "                                         
## 6  ( 1 ) " "                                         
## 7  ( 1 ) " "                                         
## 8  ( 1 ) " "                                         
##          district_price_groupB:host_is_superhostTRUE
## 1  ( 1 ) " "                                        
## 2  ( 1 ) " "                                        
## 3  ( 1 ) " "                                        
## 4  ( 1 ) " "                                        
## 5  ( 1 ) " "                                        
## 6  ( 1 ) " "                                        
## 7  ( 1 ) " "                                        
## 8  ( 1 ) " "                                        
##          district_price_groupC:host_is_superhostTRUE
## 1  ( 1 ) " "                                        
## 2  ( 1 ) " "                                        
## 3  ( 1 ) " "                                        
## 4  ( 1 ) " "                                        
## 5  ( 1 ) " "                                        
## 6  ( 1 ) " "                                        
## 7  ( 1 ) " "                                        
## 8  ( 1 ) "*"                                        
##          district_price_groupD:host_is_superhostTRUE
## 1  ( 1 ) " "                                        
## 2  ( 1 ) " "                                        
## 3  ( 1 ) " "                                        
## 4  ( 1 ) " "                                        
## 5  ( 1 ) " "                                        
## 6  ( 1 ) " "                                        
## 7  ( 1 ) " "                                        
## 8  ( 1 ) " "                                        
##          district_price_groupE:host_is_superhostTRUE
## 1  ( 1 ) " "                                        
## 2  ( 1 ) " "                                        
## 3  ( 1 ) " "                                        
## 4  ( 1 ) " "                                        
## 5  ( 1 ) " "                                        
## 6  ( 1 ) " "                                        
## 7  ( 1 ) " "                                        
## 8  ( 1 ) " "                                        
##          district_price_groupB:host_exp_days
## 1  ( 1 ) " "                                
## 2  ( 1 ) " "                                
## 3  ( 1 ) " "                                
## 4  ( 1 ) " "                                
## 5  ( 1 ) " "                                
## 6  ( 1 ) " "                                
## 7  ( 1 ) " "                                
## 8  ( 1 ) " "                                
##          district_price_groupC:host_exp_days
## 1  ( 1 ) " "                                
## 2  ( 1 ) " "                                
## 3  ( 1 ) " "                                
## 4  ( 1 ) " "                                
## 5  ( 1 ) " "                                
## 6  ( 1 ) " "                                
## 7  ( 1 ) " "                                
## 8  ( 1 ) " "                                
##          district_price_groupD:host_exp_days
## 1  ( 1 ) " "                                
## 2  ( 1 ) " "                                
## 3  ( 1 ) " "                                
## 4  ( 1 ) " "                                
## 5  ( 1 ) " "                                
## 6  ( 1 ) " "                                
## 7  ( 1 ) " "                                
## 8  ( 1 ) " "                                
##          district_price_groupE:host_exp_days
## 1  ( 1 ) " "                                
## 2  ( 1 ) " "                                
## 3  ( 1 ) " "                                
## 4  ( 1 ) " "                                
## 5  ( 1 ) " "                                
## 6  ( 1 ) " "                                
## 7  ( 1 ) " "                                
## 8  ( 1 ) " "                                
##          district_price_groupB:review_scores_rating
## 1  ( 1 ) " "                                       
## 2  ( 1 ) " "                                       
## 3  ( 1 ) " "                                       
## 4  ( 1 ) " "                                       
## 5  ( 1 ) " "                                       
## 6  ( 1 ) " "                                       
## 7  ( 1 ) "*"                                       
## 8  ( 1 ) "*"                                       
##          district_price_groupC:review_scores_rating
## 1  ( 1 ) " "                                       
## 2  ( 1 ) " "                                       
## 3  ( 1 ) " "                                       
## 4  ( 1 ) " "                                       
## 5  ( 1 ) " "                                       
## 6  ( 1 ) " "                                       
## 7  ( 1 ) " "                                       
## 8  ( 1 ) " "                                       
##          district_price_groupD:review_scores_rating
## 1  ( 1 ) " "                                       
## 2  ( 1 ) " "                                       
## 3  ( 1 ) " "                                       
## 4  ( 1 ) " "                                       
## 5  ( 1 ) " "                                       
## 6  ( 1 ) " "                                       
## 7  ( 1 ) " "                                       
## 8  ( 1 ) " "                                       
##          district_price_groupE:review_scores_rating
## 1  ( 1 ) " "                                       
## 2  ( 1 ) " "                                       
## 3  ( 1 ) " "                                       
## 4  ( 1 ) " "                                       
## 5  ( 1 ) " "                                       
## 6  ( 1 ) " "                                       
## 7  ( 1 ) " "                                       
## 8  ( 1 ) " "                                       
##          district_price_groupB:reviewedAlarmOn
## 1  ( 1 ) " "                                  
## 2  ( 1 ) " "                                  
## 3  ( 1 ) " "                                  
## 4  ( 1 ) " "                                  
## 5  ( 1 ) " "                                  
## 6  ( 1 ) " "                                  
## 7  ( 1 ) " "                                  
## 8  ( 1 ) " "                                  
##          district_price_groupC:reviewedAlarmOn
## 1  ( 1 ) " "                                  
## 2  ( 1 ) " "                                  
## 3  ( 1 ) " "                                  
## 4  ( 1 ) " "                                  
## 5  ( 1 ) " "                                  
## 6  ( 1 ) " "                                  
## 7  ( 1 ) " "                                  
## 8  ( 1 ) " "                                  
##          district_price_groupD:reviewedAlarmOn
## 1  ( 1 ) " "                                  
## 2  ( 1 ) " "                                  
## 3  ( 1 ) " "                                  
## 4  ( 1 ) " "                                  
## 5  ( 1 ) " "                                  
## 6  ( 1 ) " "                                  
## 7  ( 1 ) " "                                  
## 8  ( 1 ) " "                                  
##          district_price_groupE:reviewedAlarmOn district_price_groupB:dist_sol
## 1  ( 1 ) " "                                   " "                           
## 2  ( 1 ) " "                                   " "                           
## 3  ( 1 ) " "                                   " "                           
## 4  ( 1 ) " "                                   " "                           
## 5  ( 1 ) " "                                   " "                           
## 6  ( 1 ) " "                                   " "                           
## 7  ( 1 ) " "                                   " "                           
## 8  ( 1 ) " "                                   " "                           
##          district_price_groupC:dist_sol district_price_groupD:dist_sol
## 1  ( 1 ) " "                            " "                           
## 2  ( 1 ) " "                            "*"                           
## 3  ( 1 ) " "                            "*"                           
## 4  ( 1 ) " "                            "*"                           
## 5  ( 1 ) " "                            "*"                           
## 6  ( 1 ) " "                            "*"                           
## 7  ( 1 ) " "                            "*"                           
## 8  ( 1 ) " "                            "*"                           
##          district_price_groupE:dist_sol district_price_groupB:reviews_per_month
## 1  ( 1 ) " "                            " "                                    
## 2  ( 1 ) " "                            " "                                    
## 3  ( 1 ) "*"                            " "                                    
## 4  ( 1 ) "*"                            " "                                    
## 5  ( 1 ) "*"                            " "                                    
## 6  ( 1 ) "*"                            " "                                    
## 7  ( 1 ) "*"                            " "                                    
## 8  ( 1 ) "*"                            " "                                    
##          district_price_groupC:reviews_per_month
## 1  ( 1 ) " "                                    
## 2  ( 1 ) " "                                    
## 3  ( 1 ) " "                                    
## 4  ( 1 ) " "                                    
## 5  ( 1 ) " "                                    
## 6  ( 1 ) " "                                    
## 7  ( 1 ) " "                                    
## 8  ( 1 ) " "                                    
##          district_price_groupD:reviews_per_month
## 1  ( 1 ) " "                                    
## 2  ( 1 ) " "                                    
## 3  ( 1 ) " "                                    
## 4  ( 1 ) " "                                    
## 5  ( 1 ) " "                                    
## 6  ( 1 ) " "                                    
## 7  ( 1 ) " "                                    
## 8  ( 1 ) " "                                    
##          district_price_groupE:reviews_per_month
## 1  ( 1 ) " "                                    
## 2  ( 1 ) " "                                    
## 3  ( 1 ) " "                                    
## 4  ( 1 ) " "                                    
## 5  ( 1 ) " "                                    
## 6  ( 1 ) " "                                    
## 7  ( 1 ) " "                                    
## 8  ( 1 ) " "

Para evaluar los resultados obtenidos, se ha observado:

  • El coeficiente R2 ajustado asociado a cada modelo
## [1] 0.5773847 0.5980773 0.6109850 0.6137399 0.6157403 0.6184062 0.6201189
## [8] 0.6209463
  • El criterio BIC asociado a cada modelo
## [1]  -9994.81 -10570.05 -10941.15 -11015.41 -11067.41 -11139.98 -11183.92
## [8] -11200.90
  • El criterio CP asociado a cada modelo
## [1] 1456.1037  816.7368  418.3287  334.0711  273.1635  191.6846  139.6998
## [8]  115.1015

La mejor opción una vez más es el modelo 8, con los coeficientes:

##                                 (Intercept) 
##                                  3.70204559 
##                                accommodates 
##                                  0.81395944 
##                       host_is_superhostTRUE 
##                                  0.02461781 
##                                    dist_sol 
##                                 -0.06071184 
##                           reviews_per_month 
##                                 -0.02695011 
## district_price_groupC:host_is_superhostTRUE 
##                                  0.10494696 
##  district_price_groupB:review_scores_rating 
##                                  0.02329780 
##              district_price_groupD:dist_sol 
##                                 -0.02197519 
##              district_price_groupE:dist_sol 
##                                 -0.03321612


Validación del modelo

Podemos concluir que las tres técnicas de selección automática de variables indican que el número óptimo de predictores es 8. Además, según estas técnicas, las variables más significativas para el modelo serían:

  • accommodates

  • host_is_superhost

  • dist_sol

  • reviews_per_month

  • district_price_group C según el host_is_superhost

  • district_price_group B según el host_exp_days

  • district_price_group D según dist_sol

  • district_price_group E según dist_sol

Comprobamos este modelo:

## Analysis of Variance Table
## 
## Response: y
##                                                Df  Sum Sq Mean Sq   F value
## accommodates                                    1 3132.58 3132.58 17695.927
## host_is_superhostTRUE                           1   11.94   11.94    67.467
## dist_sol                                        1   89.83   89.83   507.421
## reviews_per_month                               1   17.44   17.44    98.521
## host_is_superhostTRUE:district_price_groupC     1    8.69    8.69    49.062
## district_price_groupB:host_exp_days             1   49.49   49.49   279.565
## dist_sol:district_price_groupD                  1   26.01   26.01   146.952
## dist_sol:district_price_groupE                  1   32.85   32.85   185.572
## Residuals                                   11616 2056.30    0.18          
##                                                Pr(>F)    
## accommodates                                < 2.2e-16 ***
## host_is_superhostTRUE                       2.369e-16 ***
## dist_sol                                    < 2.2e-16 ***
## reviews_per_month                           < 2.2e-16 ***
## host_is_superhostTRUE:district_price_groupC 2.617e-12 ***
## district_price_groupB:host_exp_days         < 2.2e-16 ***
## dist_sol:district_price_groupD              < 2.2e-16 ***
## dist_sol:district_price_groupE              < 2.2e-16 ***
## Residuals                                                
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

## 
## Call:
## lm(formula = y ~ accommodates + host_is_superhostTRUE + dist_sol + 
##     district_price_groupC:host_is_superhostTRUE + district_price_groupB:host_exp_days + 
##     district_price_groupD:dist_sol + district_price_groupE:dist_sol + 
##     reviews_per_month, data = data_new)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -2.33787 -0.27538  0.00009  0.28265  1.37442 
## 
## Coefficients:
##                                               Estimate Std. Error t value
## (Intercept)                                  3.680e+00  3.585e-02 102.654
## accommodates                                 8.143e-01  6.747e-03 120.693
## host_is_superhostTRUE                        3.103e-02  1.649e-02   1.882
## dist_sol                                    -5.692e-02  4.838e-03 -11.765
## reviews_per_month                           -2.579e-02  2.832e-03  -9.107
## host_is_superhostTRUE:district_price_groupC  9.374e-02  2.016e-02   4.651
## district_price_groupB:host_exp_days          4.683e-05  5.798e-06   8.077
## dist_sol:district_price_groupD              -2.315e-02  1.485e-03 -15.589
## dist_sol:district_price_groupE              -3.446e-02  2.530e-03 -13.622
##                                             Pr(>|t|)    
## (Intercept)                                  < 2e-16 ***
## accommodates                                 < 2e-16 ***
## host_is_superhostTRUE                         0.0599 .  
## dist_sol                                     < 2e-16 ***
## reviews_per_month                            < 2e-16 ***
## host_is_superhostTRUE:district_price_groupC 3.35e-06 ***
## district_price_groupB:host_exp_days         7.30e-16 ***
## dist_sol:district_price_groupD               < 2e-16 ***
## dist_sol:district_price_groupE               < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.4207 on 11616 degrees of freedom
## Multiple R-squared:  0.621,  Adjusted R-squared:  0.6207 
## F-statistic:  2379 on 8 and 11616 DF,  p-value: < 2.2e-16
## 
## 
## ASSESSMENT OF THE LINEAR MODEL ASSUMPTIONS
## USING THE GLOBAL TEST ON 4 DEGREES-OF-FREEDOM:
## Level of Significance =  0.05 
## 
## Call:
##  gvlma(x = fit_5) 
## 
##                      Value   p-value                   Decision
## Global Stat        169.250 0.000e+00 Assumptions NOT satisfied!
## Skewness            77.826 0.000e+00 Assumptions NOT satisfied!
## Kurtosis            74.728 0.000e+00 Assumptions NOT satisfied!
## Link Function       16.267 5.501e-05 Assumptions NOT satisfied!
## Heteroscedasticity   0.429 5.125e-01    Assumptions acceptable.

Observamos que este modelo no cumple con todas las condiciones básicas, ya que los residuos no siguen una distribución normal, y por tanto tampoco podemos concluir que los coeficientes de los regresores sigan una distribución normal. Atendiendo a nuestra valoración, vamos a probar a eliminar las observaciones cuyo precio por noche es inferior a 3 euros.

Comprobemos cómo ha afectado este cambio:

## Subset selection object
## Call: regsubsets.formula(log(price) ~ accommodates * district_price_group + 
##     minimum_nights_avg_ntm * district_price_group + host_is_superhost * 
##     district_price_group + host_exp_days * district_price_group + 
##     review_scores_rating * district_price_group + reviewedAlarm * 
##     district_price_group + dist_sol * district_price_group + 
##     reviews_per_month * district_price_group, data_train_sel, 
##     method = "forward")
## 44 Variables  (and intercept)
##                                              Forced in Forced out
## accommodates                                     FALSE      FALSE
## district_price_groupB                            FALSE      FALSE
## district_price_groupC                            FALSE      FALSE
## district_price_groupD                            FALSE      FALSE
## district_price_groupE                            FALSE      FALSE
## minimum_nights_avg_ntm                           FALSE      FALSE
## host_is_superhostTRUE                            FALSE      FALSE
## host_exp_days                                    FALSE      FALSE
## review_scores_rating                             FALSE      FALSE
## reviewedAlarmOn                                  FALSE      FALSE
## dist_sol                                         FALSE      FALSE
## reviews_per_month                                FALSE      FALSE
## accommodates:district_price_groupB               FALSE      FALSE
## accommodates:district_price_groupC               FALSE      FALSE
## accommodates:district_price_groupD               FALSE      FALSE
## accommodates:district_price_groupE               FALSE      FALSE
## district_price_groupB:minimum_nights_avg_ntm     FALSE      FALSE
## district_price_groupC:minimum_nights_avg_ntm     FALSE      FALSE
## district_price_groupD:minimum_nights_avg_ntm     FALSE      FALSE
## district_price_groupE:minimum_nights_avg_ntm     FALSE      FALSE
## district_price_groupB:host_is_superhostTRUE      FALSE      FALSE
## district_price_groupC:host_is_superhostTRUE      FALSE      FALSE
## district_price_groupD:host_is_superhostTRUE      FALSE      FALSE
## district_price_groupE:host_is_superhostTRUE      FALSE      FALSE
## district_price_groupB:host_exp_days              FALSE      FALSE
## district_price_groupC:host_exp_days              FALSE      FALSE
## district_price_groupD:host_exp_days              FALSE      FALSE
## district_price_groupE:host_exp_days              FALSE      FALSE
## district_price_groupB:review_scores_rating       FALSE      FALSE
## district_price_groupC:review_scores_rating       FALSE      FALSE
## district_price_groupD:review_scores_rating       FALSE      FALSE
## district_price_groupE:review_scores_rating       FALSE      FALSE
## district_price_groupB:reviewedAlarmOn            FALSE      FALSE
## district_price_groupC:reviewedAlarmOn            FALSE      FALSE
## district_price_groupD:reviewedAlarmOn            FALSE      FALSE
## district_price_groupE:reviewedAlarmOn            FALSE      FALSE
## district_price_groupB:dist_sol                   FALSE      FALSE
## district_price_groupC:dist_sol                   FALSE      FALSE
## district_price_groupD:dist_sol                   FALSE      FALSE
## district_price_groupE:dist_sol                   FALSE      FALSE
## district_price_groupB:reviews_per_month          FALSE      FALSE
## district_price_groupC:reviews_per_month          FALSE      FALSE
## district_price_groupD:reviews_per_month          FALSE      FALSE
## district_price_groupE:reviews_per_month          FALSE      FALSE
## 1 subsets of each size up to 8
## Selection Algorithm: forward
##          accommodates district_price_groupB district_price_groupC
## 1  ( 1 ) "*"          " "                   " "                  
## 2  ( 1 ) "*"          " "                   " "                  
## 3  ( 1 ) "*"          " "                   " "                  
## 4  ( 1 ) "*"          " "                   " "                  
## 5  ( 1 ) "*"          " "                   " "                  
## 6  ( 1 ) "*"          " "                   " "                  
## 7  ( 1 ) "*"          " "                   " "                  
## 8  ( 1 ) "*"          " "                   " "                  
##          district_price_groupD district_price_groupE minimum_nights_avg_ntm
## 1  ( 1 ) " "                   " "                   " "                   
## 2  ( 1 ) " "                   " "                   " "                   
## 3  ( 1 ) " "                   " "                   " "                   
## 4  ( 1 ) " "                   " "                   " "                   
## 5  ( 1 ) " "                   " "                   " "                   
## 6  ( 1 ) " "                   " "                   " "                   
## 7  ( 1 ) " "                   " "                   " "                   
## 8  ( 1 ) " "                   " "                   " "                   
##          host_is_superhostTRUE host_exp_days review_scores_rating
## 1  ( 1 ) " "                   " "           " "                 
## 2  ( 1 ) " "                   " "           " "                 
## 3  ( 1 ) " "                   " "           " "                 
## 4  ( 1 ) " "                   " "           " "                 
## 5  ( 1 ) " "                   " "           " "                 
## 6  ( 1 ) "*"                   " "           " "                 
## 7  ( 1 ) "*"                   " "           " "                 
## 8  ( 1 ) "*"                   " "           " "                 
##          reviewedAlarmOn dist_sol reviews_per_month
## 1  ( 1 ) " "             " "      " "              
## 2  ( 1 ) " "             " "      " "              
## 3  ( 1 ) " "             " "      " "              
## 4  ( 1 ) " "             "*"      " "              
## 5  ( 1 ) " "             "*"      "*"              
## 6  ( 1 ) " "             "*"      "*"              
## 7  ( 1 ) " "             "*"      "*"              
## 8  ( 1 ) " "             "*"      "*"              
##          accommodates:district_price_groupB accommodates:district_price_groupC
## 1  ( 1 ) " "                                " "                               
## 2  ( 1 ) " "                                " "                               
## 3  ( 1 ) " "                                " "                               
## 4  ( 1 ) " "                                " "                               
## 5  ( 1 ) " "                                " "                               
## 6  ( 1 ) " "                                " "                               
## 7  ( 1 ) " "                                " "                               
## 8  ( 1 ) " "                                " "                               
##          accommodates:district_price_groupD accommodates:district_price_groupE
## 1  ( 1 ) " "                                " "                               
## 2  ( 1 ) " "                                " "                               
## 3  ( 1 ) " "                                " "                               
## 4  ( 1 ) " "                                " "                               
## 5  ( 1 ) " "                                " "                               
## 6  ( 1 ) " "                                " "                               
## 7  ( 1 ) " "                                " "                               
## 8  ( 1 ) " "                                " "                               
##          district_price_groupB:minimum_nights_avg_ntm
## 1  ( 1 ) " "                                         
## 2  ( 1 ) " "                                         
## 3  ( 1 ) " "                                         
## 4  ( 1 ) " "                                         
## 5  ( 1 ) " "                                         
## 6  ( 1 ) " "                                         
## 7  ( 1 ) " "                                         
## 8  ( 1 ) " "                                         
##          district_price_groupC:minimum_nights_avg_ntm
## 1  ( 1 ) " "                                         
## 2  ( 1 ) " "                                         
## 3  ( 1 ) " "                                         
## 4  ( 1 ) " "                                         
## 5  ( 1 ) " "                                         
## 6  ( 1 ) " "                                         
## 7  ( 1 ) " "                                         
## 8  ( 1 ) " "                                         
##          district_price_groupD:minimum_nights_avg_ntm
## 1  ( 1 ) " "                                         
## 2  ( 1 ) " "                                         
## 3  ( 1 ) " "                                         
## 4  ( 1 ) " "                                         
## 5  ( 1 ) " "                                         
## 6  ( 1 ) " "                                         
## 7  ( 1 ) " "                                         
## 8  ( 1 ) " "                                         
##          district_price_groupE:minimum_nights_avg_ntm
## 1  ( 1 ) " "                                         
## 2  ( 1 ) " "                                         
## 3  ( 1 ) " "                                         
## 4  ( 1 ) " "                                         
## 5  ( 1 ) " "                                         
## 6  ( 1 ) " "                                         
## 7  ( 1 ) " "                                         
## 8  ( 1 ) " "                                         
##          district_price_groupB:host_is_superhostTRUE
## 1  ( 1 ) " "                                        
## 2  ( 1 ) " "                                        
## 3  ( 1 ) " "                                        
## 4  ( 1 ) " "                                        
## 5  ( 1 ) " "                                        
## 6  ( 1 ) " "                                        
## 7  ( 1 ) " "                                        
## 8  ( 1 ) " "                                        
##          district_price_groupC:host_is_superhostTRUE
## 1  ( 1 ) " "                                        
## 2  ( 1 ) " "                                        
## 3  ( 1 ) " "                                        
## 4  ( 1 ) " "                                        
## 5  ( 1 ) " "                                        
## 6  ( 1 ) " "                                        
## 7  ( 1 ) " "                                        
## 8  ( 1 ) "*"                                        
##          district_price_groupD:host_is_superhostTRUE
## 1  ( 1 ) " "                                        
## 2  ( 1 ) " "                                        
## 3  ( 1 ) " "                                        
## 4  ( 1 ) " "                                        
## 5  ( 1 ) " "                                        
## 6  ( 1 ) " "                                        
## 7  ( 1 ) " "                                        
## 8  ( 1 ) " "                                        
##          district_price_groupE:host_is_superhostTRUE
## 1  ( 1 ) " "                                        
## 2  ( 1 ) " "                                        
## 3  ( 1 ) " "                                        
## 4  ( 1 ) " "                                        
## 5  ( 1 ) " "                                        
## 6  ( 1 ) " "                                        
## 7  ( 1 ) " "                                        
## 8  ( 1 ) " "                                        
##          district_price_groupB:host_exp_days
## 1  ( 1 ) " "                                
## 2  ( 1 ) " "                                
## 3  ( 1 ) " "                                
## 4  ( 1 ) " "                                
## 5  ( 1 ) " "                                
## 6  ( 1 ) " "                                
## 7  ( 1 ) " "                                
## 8  ( 1 ) " "                                
##          district_price_groupC:host_exp_days
## 1  ( 1 ) " "                                
## 2  ( 1 ) " "                                
## 3  ( 1 ) " "                                
## 4  ( 1 ) " "                                
## 5  ( 1 ) " "                                
## 6  ( 1 ) " "                                
## 7  ( 1 ) " "                                
## 8  ( 1 ) " "                                
##          district_price_groupD:host_exp_days
## 1  ( 1 ) " "                                
## 2  ( 1 ) " "                                
## 3  ( 1 ) " "                                
## 4  ( 1 ) " "                                
## 5  ( 1 ) " "                                
## 6  ( 1 ) " "                                
## 7  ( 1 ) " "                                
## 8  ( 1 ) " "                                
##          district_price_groupE:host_exp_days
## 1  ( 1 ) " "                                
## 2  ( 1 ) " "                                
## 3  ( 1 ) " "                                
## 4  ( 1 ) " "                                
## 5  ( 1 ) " "                                
## 6  ( 1 ) " "                                
## 7  ( 1 ) " "                                
## 8  ( 1 ) " "                                
##          district_price_groupB:review_scores_rating
## 1  ( 1 ) " "                                       
## 2  ( 1 ) " "                                       
## 3  ( 1 ) " "                                       
## 4  ( 1 ) " "                                       
## 5  ( 1 ) " "                                       
## 6  ( 1 ) " "                                       
## 7  ( 1 ) "*"                                       
## 8  ( 1 ) "*"                                       
##          district_price_groupC:review_scores_rating
## 1  ( 1 ) " "                                       
## 2  ( 1 ) " "                                       
## 3  ( 1 ) " "                                       
## 4  ( 1 ) " "                                       
## 5  ( 1 ) " "                                       
## 6  ( 1 ) " "                                       
## 7  ( 1 ) " "                                       
## 8  ( 1 ) " "                                       
##          district_price_groupD:review_scores_rating
## 1  ( 1 ) " "                                       
## 2  ( 1 ) " "                                       
## 3  ( 1 ) " "                                       
## 4  ( 1 ) " "                                       
## 5  ( 1 ) " "                                       
## 6  ( 1 ) " "                                       
## 7  ( 1 ) " "                                       
## 8  ( 1 ) " "                                       
##          district_price_groupE:review_scores_rating
## 1  ( 1 ) " "                                       
## 2  ( 1 ) " "                                       
## 3  ( 1 ) " "                                       
## 4  ( 1 ) " "                                       
## 5  ( 1 ) " "                                       
## 6  ( 1 ) " "                                       
## 7  ( 1 ) " "                                       
## 8  ( 1 ) " "                                       
##          district_price_groupB:reviewedAlarmOn
## 1  ( 1 ) " "                                  
## 2  ( 1 ) " "                                  
## 3  ( 1 ) " "                                  
## 4  ( 1 ) " "                                  
## 5  ( 1 ) " "                                  
## 6  ( 1 ) " "                                  
## 7  ( 1 ) " "                                  
## 8  ( 1 ) " "                                  
##          district_price_groupC:reviewedAlarmOn
## 1  ( 1 ) " "                                  
## 2  ( 1 ) " "                                  
## 3  ( 1 ) " "                                  
## 4  ( 1 ) " "                                  
## 5  ( 1 ) " "                                  
## 6  ( 1 ) " "                                  
## 7  ( 1 ) " "                                  
## 8  ( 1 ) " "                                  
##          district_price_groupD:reviewedAlarmOn
## 1  ( 1 ) " "                                  
## 2  ( 1 ) " "                                  
## 3  ( 1 ) " "                                  
## 4  ( 1 ) " "                                  
## 5  ( 1 ) " "                                  
## 6  ( 1 ) " "                                  
## 7  ( 1 ) " "                                  
## 8  ( 1 ) " "                                  
##          district_price_groupE:reviewedAlarmOn district_price_groupB:dist_sol
## 1  ( 1 ) " "                                   " "                           
## 2  ( 1 ) " "                                   " "                           
## 3  ( 1 ) " "                                   " "                           
## 4  ( 1 ) " "                                   " "                           
## 5  ( 1 ) " "                                   " "                           
## 6  ( 1 ) " "                                   " "                           
## 7  ( 1 ) " "                                   " "                           
## 8  ( 1 ) " "                                   " "                           
##          district_price_groupC:dist_sol district_price_groupD:dist_sol
## 1  ( 1 ) " "                            " "                           
## 2  ( 1 ) " "                            "*"                           
## 3  ( 1 ) " "                            "*"                           
## 4  ( 1 ) " "                            "*"                           
## 5  ( 1 ) " "                            "*"                           
## 6  ( 1 ) " "                            "*"                           
## 7  ( 1 ) " "                            "*"                           
## 8  ( 1 ) " "                            "*"                           
##          district_price_groupE:dist_sol district_price_groupB:reviews_per_month
## 1  ( 1 ) " "                            " "                                    
## 2  ( 1 ) " "                            " "                                    
## 3  ( 1 ) "*"                            " "                                    
## 4  ( 1 ) "*"                            " "                                    
## 5  ( 1 ) "*"                            " "                                    
## 6  ( 1 ) "*"                            " "                                    
## 7  ( 1 ) "*"                            " "                                    
## 8  ( 1 ) "*"                            " "                                    
##          district_price_groupC:reviews_per_month
## 1  ( 1 ) " "                                    
## 2  ( 1 ) " "                                    
## 3  ( 1 ) " "                                    
## 4  ( 1 ) " "                                    
## 5  ( 1 ) " "                                    
## 6  ( 1 ) " "                                    
## 7  ( 1 ) " "                                    
## 8  ( 1 ) " "                                    
##          district_price_groupD:reviews_per_month
## 1  ( 1 ) " "                                    
## 2  ( 1 ) " "                                    
## 3  ( 1 ) " "                                    
## 4  ( 1 ) " "                                    
## 5  ( 1 ) " "                                    
## 6  ( 1 ) " "                                    
## 7  ( 1 ) " "                                    
## 8  ( 1 ) " "                                    
##          district_price_groupE:reviews_per_month
## 1  ( 1 ) " "                                    
## 2  ( 1 ) " "                                    
## 3  ( 1 ) " "                                    
## 4  ( 1 ) " "                                    
## 5  ( 1 ) " "                                    
## 6  ( 1 ) " "                                    
## 7  ( 1 ) " "                                    
## 8  ( 1 ) " "

Para evaluar los resultados obtenidos, se ha observado:

  • El coeficiente R2 ajustado asociado a cada modelo
## [1] 0.5838784 0.6045102 0.6174491 0.6198355 0.6219973 0.6245647 0.6264572
## [8] 0.6273434
  • El criterio BIC asociado a cada modelo
## [1] -10166.93 -10749.27 -11127.30 -11191.63 -11249.51 -11320.32 -11370.66
## [8] -11389.89
  • El criterio CP asociado a cada modelo
## [1] 1475.2119  827.2625  421.3282  347.2556  280.2622  200.5250  142.0206
## [8]  115.1551

La mejor opción es el modelo 8, con los coeficientes:

##                                 (Intercept) 
##                                  3.68185683 
##                                accommodates 
##                                  0.82084569 
##                       host_is_superhostTRUE 
##                                  0.02062716 
##                                    dist_sol 
##                                 -0.05878069 
##                           reviews_per_month 
##                                 -0.02762681 
## district_price_groupC:host_is_superhostTRUE 
##                                  0.10833945 
##  district_price_groupB:review_scores_rating 
##                                  0.02439940 
##              district_price_groupD:dist_sol 
##                                 -0.02196658 
##              district_price_groupE:dist_sol 
##                                 -0.03337149
## Analysis of Variance Table
## 
## Response: y
##                                                Df  Sum Sq Mean Sq   F value
## accommodates                                    1 3161.08 3161.08 18199.499
## host_is_superhostTRUE                           1   11.16   11.16    64.278
## dist_sol                                        1   85.40   85.40   491.661
## reviews_per_month                               1   18.32   18.32   105.485
## host_is_superhostTRUE:district_price_groupC     1    8.89    8.89    51.208
## district_price_groupB:review_scores_rating      1   62.13   62.13   357.715
## dist_sol:district_price_groupD                  1   20.50   20.50   118.038
## dist_sol:district_price_groupE                  1   30.09   30.09   173.218
## Residuals                                   11607 2016.03    0.17          
##                                                Pr(>F)    
## accommodates                                < 2.2e-16 ***
## host_is_superhostTRUE                       1.184e-15 ***
## dist_sol                                    < 2.2e-16 ***
## reviews_per_month                           < 2.2e-16 ***
## host_is_superhostTRUE:district_price_groupC 8.807e-13 ***
## district_price_groupB:review_scores_rating  < 2.2e-16 ***
## dist_sol:district_price_groupD              < 2.2e-16 ***
## dist_sol:district_price_groupE              < 2.2e-16 ***
## Residuals                                                
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

## 
## Call:
## lm(formula = y ~ accommodates + host_is_superhostTRUE + dist_sol + 
##     district_price_groupC:host_is_superhostTRUE + district_price_groupB:review_scores_rating + 
##     district_price_groupD:dist_sol + district_price_groupE:dist_sol + 
##     reviews_per_month, data = data_new)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -1.87472 -0.27484 -0.00087  0.28237  1.37154 
## 
## Coefficients:
##                                              Estimate Std. Error t value
## (Intercept)                                  3.681857   0.036123 101.924
## accommodates                                 0.820846   0.006702 122.474
## host_is_superhostTRUE                        0.020627   0.016464   1.253
## dist_sol                                    -0.058781   0.004924 -11.937
## reviews_per_month                           -0.027627   0.002798  -9.875
## host_is_superhostTRUE:district_price_groupC  0.108339   0.020257   5.348
## district_price_groupB:review_scores_rating   0.024399   0.002712   8.996
## dist_sol:district_price_groupD              -0.021967   0.001516 -14.491
## dist_sol:district_price_groupE              -0.033371   0.002536 -13.161
##                                             Pr(>|t|)    
## (Intercept)                                  < 2e-16 ***
## accommodates                                 < 2e-16 ***
## host_is_superhostTRUE                           0.21    
## dist_sol                                     < 2e-16 ***
## reviews_per_month                            < 2e-16 ***
## host_is_superhostTRUE:district_price_groupC 9.05e-08 ***
## district_price_groupB:review_scores_rating   < 2e-16 ***
## dist_sol:district_price_groupD               < 2e-16 ***
## dist_sol:district_price_groupE               < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.4168 on 11607 degrees of freedom
## Multiple R-squared:  0.6276, Adjusted R-squared:  0.6273 
## F-statistic:  2445 on 8 and 11607 DF,  p-value: < 2.2e-16
## 
## 
## ASSESSMENT OF THE LINEAR MODEL ASSUMPTIONS
## USING THE GLOBAL TEST ON 4 DEGREES-OF-FREEDOM:
## Level of Significance =  0.05 
## 
## Call:
##  gvlma(x = fit_5) 
## 
##                       Value   p-value                   Decision
## Global Stat        65.86940 1.688e-13 Assumptions NOT satisfied!
## Skewness           34.82088 3.615e-09 Assumptions NOT satisfied!
## Kurtosis            2.59355 1.073e-01    Assumptions acceptable.
## Link Function      28.44198 9.655e-08 Assumptions NOT satisfied!
## Heteroscedasticity  0.01299 9.093e-01    Assumptions acceptable.

Estudiamos la normalidad de los residuos del modelo:

## 
##  Lilliefors (Kolmogorov-Smirnov) normality test
## 
## data:  fit_5$residuals
## D = 0.010458, p-value = 0.006284

Vemos que a pesar de la mejora en las métricas del modelo, seguimos sin obtener un modelo lineal suficientemente adecuado.


Técnicas de regularización

Además de las técnicas de selección de variables anteriores, vamos también a probar con técnicas de regularización. Para lo siguiente, hay que tener en cuenta que con el método Lasso se consigue que ciertos coeficientes se anulen, mientras que con el método Ridge se situarían muy cercanos a 0, pero sin llegar a anularse.


Regularización Lasso

En la siguiente gráfica se muestra como varía el valor de los coeficientes para diferentes valores de lambda, hasta que finalmente se hacen todos 0 (esto con Ridge no ocurriría).

Para descubrir con qué valor de lambda se consigue el mejor modelo, y con cuántos predictores, el paquete ‘glmnet’ ofrece una función para averiguarlo. Para la evaluación de los modelos, utiliza la técnica de validación cruzada y una función de pérdida que por defecto es el error cuadrático medio.

En la gráfica podemos apreciar dos líneas de puntos. La primera marca el lambda para el cual se consigue el modelo con un error cuadrático medio más bajo. La segunda, marca el lambda para el cual se consigue el modelo más sencillo cuyo error se encuentra a 1 desviación típica del mínimo.

En esta misma gráfica, podemos observar que se podría obtener un modelo con 17 predictores aproximadamente, cuyo error sería muy similar al del mejor modelo (que utiliza 43).

## 
## Call:  cv.glmnet(x = x, y = y, alpha = 1) 
## 
## Measure: Mean-Squared Error 
## 
##       Lambda Index Measure       SE Nonzero
## min 0.000052   100  0.1729 0.001494      43
## 1se 0.009550    44  0.1742 0.001556      17
##                                  (Intercept) 
##                                 3.619088e+00 
##                                 accommodates 
##                                 7.747231e-01 
##                        host_is_superhostTRUE 
##                                 9.327038e-04 
##                         review_scores_rating 
##                                 1.657591e-03 
##                                     dist_sol 
##                                -4.957111e-02 
##                            reviews_per_month 
##                                -1.619913e-02 
##           accommodates:district_price_groupB 
##                                 5.159984e-02 
##           accommodates:district_price_groupC 
##                                 4.082319e-02 
## district_price_groupB:minimum_nights_avg_ntm 
##                                 1.562479e-02 
## district_price_groupC:minimum_nights_avg_ntm 
##                                 1.120653e-02 
## district_price_groupD:minimum_nights_avg_ntm 
##                                -2.222144e-02 
##  district_price_groupC:host_is_superhostTRUE 
##                                 9.070019e-02 
##          district_price_groupB:host_exp_days 
##                                 1.092276e-05 
##          district_price_groupE:host_exp_days 
##                                -2.043379e-05 
##   district_price_groupB:review_scores_rating 
##                                 1.099961e-02 
##   district_price_groupD:review_scores_rating 
##                                -3.821590e-03

La información que obtenemos al aplicar regularización Lasso es parecida a la que obteníamos con las técnicas aplicadas anteriormente. Se obtiene un SE de 0.001556 con 17 variables, y 0.001494 con 43.

Si se calculan los residuos de este modelo, se puede observar que no siguen una distribución normal.

## 
##  Lilliefors (Kolmogorov-Smirnov) normality test
## 
## data:  residuals_lasso
## D = 0.010992, p-value = 0.003103
## [1] "R2 = 0.627844"

MSE y MAPE de entrenamiento:

## [1] "Error (mse) de entrenamiento: 0.173631547749365"
## [1] "MAPE de entrenamiento: 0.0119895338992731"


Regularización Ridge

Otra técnica de regularización que se ha aplicado es el método Ridge. En este caso, la penalización aplicada a los coeficientes reducirá los coeficientes menos importantes, pero nunca los hará completamente 0, independientemente de valor que tome lambda. Esto se puede comprobar en la siguiente gráfica:

De igual forma que con Lasso, en la siguiente gráfica se puede observar el error cuadrático medio calculado mediante validación cruzada para diferentes valores de lambda:

En este caso, se muestran los coeficientes que se obtienen del modelo cuyo error se encuentra a 1 desviación típica del mínimo (y donde empieza a incrementarse el error cuadrático medio):

##                                  (Intercept) 
##                                 3.655170e+00 
##                                 accommodates 
##                                 5.331901e-01 
##                        district_price_groupB 
##                                 9.135488e-03 
##                        district_price_groupC 
##                                -1.626451e-03 
##                        district_price_groupD 
##                                -4.341307e-02 
##                        district_price_groupE 
##                                -6.813147e-02 
##                       minimum_nights_avg_ntm 
##                                 2.079739e-02 
##                        host_is_superhostTRUE 
##                                 4.702544e-02 
##                                host_exp_days 
##                                -2.470186e-06 
##                         review_scores_rating 
##                                 1.596772e-02 
##                              reviewedAlarmOn 
##                                -8.146193e-04 
##                                     dist_sol 
##                                -5.288058e-02 
##                            reviews_per_month 
##                                -1.353862e-02 
##           accommodates:district_price_groupB 
##                                 2.235099e-01 
##           accommodates:district_price_groupC 
##                                 2.305919e-01 
##           accommodates:district_price_groupD 
##                                 1.755121e-01 
##           accommodates:district_price_groupE 
##                                 1.413392e-01 
## district_price_groupB:minimum_nights_avg_ntm 
##                                 2.775838e-02 
## district_price_groupC:minimum_nights_avg_ntm 
##                                 1.303494e-02 
## district_price_groupD:minimum_nights_avg_ntm 
##                                -5.080793e-02 
## district_price_groupE:minimum_nights_avg_ntm 
##                                 2.852133e-02 
##  district_price_groupB:host_is_superhostTRUE 
##                                -2.331325e-02 
##  district_price_groupC:host_is_superhostTRUE 
##                                 6.645847e-02 
##  district_price_groupD:host_is_superhostTRUE 
##                                 2.776415e-04 
##  district_price_groupE:host_is_superhostTRUE 
##                                -1.038600e-01 
##          district_price_groupB:host_exp_days 
##                                 1.662807e-05 
##          district_price_groupC:host_exp_days 
##                                -1.522692e-05 
##          district_price_groupD:host_exp_days 
##                                -4.028097e-06 
##          district_price_groupE:host_exp_days 
##                                -3.134738e-05 
##   district_price_groupB:review_scores_rating 
##                                 7.011341e-03 
##   district_price_groupC:review_scores_rating 
##                                 8.003232e-04 
##   district_price_groupD:review_scores_rating 
##                                -1.205387e-02 
##   district_price_groupE:review_scores_rating 
##                                -1.335010e-02 
##        district_price_groupB:reviewedAlarmOn 
##                                -3.806536e-02 
##        district_price_groupC:reviewedAlarmOn 
##                                -5.406282e-03

Con Ridge, se obtiene un SE de 0.001440 con 44 variables.

## 
## Call:  cv.glmnet(x = x, y = y, alpha = 0) 
## 
## Measure: Mean-Squared Error 
## 
##      Lambda Index Measure       SE Nonzero
## min 0.05217   100  0.1741 0.001440      44
## 1se 0.09116    94  0.1754 0.001456      44

Si se calculan los residuos de este modelo, se puede observar que no siguen una distribución normal, pero estan cercanos de ella.

## 
##  Lilliefors (Kolmogorov-Smirnov) normality test
## 
## data:  residuals_ridge
## D = 0.0091364, p-value = 0.02988
## [1] "R2 = 0.628955"

MSE y MAPE de entrenamiento:

## [1] "Error (mse) de entrenamiento: 0.174552555738292"
## [1] "MAPE de entrenamiento: 0.0129051740604042"


Construcción de los modelos de regresión lineal múltiple

Una vez que ya hemos analizado completamente nuestras variables, se ha procedido a entrenar diversos modelos manualmente y a evaluar sus resultados. A continuación se van mostrando los resultados obtenidos, analizando también sus residuos.


Modelo 1

Incluimos en el modelo aquellas variables que, según el análisis realizado y las técnicas automáticas de selección, tienen mayor influencia sobre el precio .

## 
## Call:
## lm(formula = log(price) ~ accommodates:district_price_group + 
##     dist_sol + reviews_per_month + review_scores_rating + host_is_superhost, 
##     data = data_train_sel)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -1.86726 -0.27547 -0.00051  0.28499  1.35514 
## 
## Coefficients:
##                                     Estimate Std. Error t value Pr(>|t|)    
## (Intercept)                         3.650957   0.043428  84.069  < 2e-16 ***
## dist_sol                           -0.071737   0.004745 -15.118  < 2e-16 ***
## reviews_per_month                  -0.028932   0.002877 -10.056  < 2e-16 ***
## review_scores_rating                0.018184   0.004915   3.699 0.000217 ***
## host_is_superhostTRUE               0.087611   0.010167   8.617  < 2e-16 ***
## accommodates:district_price_groupA  0.863992   0.047635  18.138  < 2e-16 ***
## accommodates:district_price_groupB  0.939240   0.010185  92.219  < 2e-16 ***
## accommodates:district_price_groupC  0.857981   0.007619 112.610  < 2e-16 ***
## accommodates:district_price_groupD  0.689436   0.010805  63.808  < 2e-16 ***
## accommodates:district_price_groupE  0.605441   0.021671  27.937  < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.4193 on 11606 degrees of freedom
## Multiple R-squared:  0.623,  Adjusted R-squared:  0.6227 
## F-statistic:  2131 on 9 and 11606 DF,  p-value: < 2.2e-16
## 
## 
## ASSESSMENT OF THE LINEAR MODEL ASSUMPTIONS
## USING THE GLOBAL TEST ON 4 DEGREES-OF-FREEDOM:
## Level of Significance =  0.05 
## 
## Call:
##  gvlma(x = fit_m3) 
## 
##                       Value   p-value                   Decision
## Global Stat        38.78891 7.702e-08 Assumptions NOT satisfied!
## Skewness           36.50925 1.519e-09 Assumptions NOT satisfied!
## Kurtosis            1.24459 2.646e-01    Assumptions acceptable.
## Link Function       1.00771 3.155e-01    Assumptions acceptable.
## Heteroscedasticity  0.02736 8.686e-01    Assumptions acceptable.

El modelo tiene relación lineal, se cumplen condiciones de Heterocedasticidad y Kurtosis.

Si se calculan los residuos de este modelo, se puede observar que no siguen una distribución normal.

## 
##  Lilliefors (Kolmogorov-Smirnov) normality test
## 
## data:  fit_m3$residuals
## D = 0.010437, p-value = 0.006461


Modelo 2

Añadimos en el primer modelo la interacción de las variables reviews_per_month y district_price_group , host_listings_count y host_is_superhost.

## 
## Call:
## lm(formula = log(price) ~ accommodates:district_price_group + 
##     dist_sol + +reviews_per_month:district_price_group + host_listings_count:host_is_superhost + 
##     review_scores_rating, data = data_train_sel)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -1.86412 -0.27581  0.00001  0.28429  1.37336 
## 
## Coefficients:
##                                             Estimate Std. Error t value
## (Intercept)                                 3.623564   0.044553  81.332
## dist_sol                                   -0.068026   0.004812 -14.137
## review_scores_rating                        0.019136   0.004923   3.887
## accommodates:district_price_groupA          0.819889   0.051356  15.965
## accommodates:district_price_groupB          0.926876   0.010800  85.822
## accommodates:district_price_groupC          0.854365   0.007713 110.771
## accommodates:district_price_groupD          0.688522   0.010987  62.669
## accommodates:district_price_groupE          0.620967   0.022343  27.793
## district_price_groupA:reviews_per_month    -0.117129   0.036381  -3.220
## district_price_groupB:reviews_per_month    -0.042061   0.006290  -6.687
## district_price_groupC:reviews_per_month    -0.026631   0.003499  -7.612
## district_price_groupD:reviews_per_month    -0.022155   0.005706  -3.883
## district_price_groupE:reviews_per_month     0.011086   0.012291   0.902
## host_listings_count:host_is_superhostFALSE  0.007871   0.007558   1.041
## host_listings_count:host_is_superhostTRUE   0.140039   0.013175  10.629
##                                            Pr(>|t|)    
## (Intercept)                                 < 2e-16 ***
## dist_sol                                    < 2e-16 ***
## review_scores_rating                       0.000102 ***
## accommodates:district_price_groupA          < 2e-16 ***
## accommodates:district_price_groupB          < 2e-16 ***
## accommodates:district_price_groupC          < 2e-16 ***
## accommodates:district_price_groupD          < 2e-16 ***
## accommodates:district_price_groupE          < 2e-16 ***
## district_price_groupA:reviews_per_month    0.001288 ** 
## district_price_groupB:reviews_per_month    2.39e-11 ***
## district_price_groupC:reviews_per_month    2.92e-14 ***
## district_price_groupD:reviews_per_month    0.000104 ***
## district_price_groupE:reviews_per_month    0.367091    
## host_listings_count:host_is_superhostFALSE 0.297720    
## host_listings_count:host_is_superhostTRUE   < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.4182 on 11601 degrees of freedom
## Multiple R-squared:  0.6252, Adjusted R-squared:  0.6247 
## F-statistic:  1382 on 14 and 11601 DF,  p-value: < 2.2e-16
## 
## 
## ASSESSMENT OF THE LINEAR MODEL ASSUMPTIONS
## USING THE GLOBAL TEST ON 4 DEGREES-OF-FREEDOM:
## Level of Significance =  0.05 
## 
## Call:
##  gvlma(x = fit_m4) 
## 
##                        Value   p-value                   Decision
## Global Stat        40.425623 3.534e-08 Assumptions NOT satisfied!
## Skewness           37.148636 1.095e-09 Assumptions NOT satisfied!
## Kurtosis            2.531869 1.116e-01    Assumptions acceptable.
## Link Function       0.741932 3.890e-01    Assumptions acceptable.
## Heteroscedasticity  0.003186 9.550e-01    Assumptions acceptable.

En este caso, finalmente obtuvimos un modelo con una distribución más o menos normal de residuos.

## 
##  Lilliefors (Kolmogorov-Smirnov) normality test
## 
## data:  fit_m4$residuals
## D = 0.0086618, p-value = 0.04901

Obtenemos métricas más o menos satisfactorias:

##        mae        mse       rmse       mape 
## 0.33290177 0.17469518 0.41796552 0.08599201

Por tanto, concluímos que este modelo es el más adecuado para nuestros objetivos, por lo que procedemos a la evaluación del modelo con los datos de test.

Funcionamiento del modelo en el test

Para empezar, haremos las mismas conversiones necesarias para los datos de test.

Imputamos datos faltantes.

## 
##  iter imp variable
##   1   1  bedrooms  beds  review_scores_rating  reviews_per_month
##   1   2  bedrooms  beds  review_scores_rating  reviews_per_month
##   1   3  bedrooms  beds  review_scores_rating  reviews_per_month
##   1   4  bedrooms  beds  review_scores_rating  reviews_per_month
##   1   5  bedrooms  beds  review_scores_rating  reviews_per_month
##   2   1  bedrooms  beds  review_scores_rating  reviews_per_month
##   2   2  bedrooms  beds  review_scores_rating  reviews_per_month
##   2   3  bedrooms  beds  review_scores_rating  reviews_per_month
##   2   4  bedrooms  beds  review_scores_rating  reviews_per_month
##   2   5  bedrooms  beds  review_scores_rating  reviews_per_month
##   3   1  bedrooms  beds  review_scores_rating  reviews_per_month
##   3   2  bedrooms  beds  review_scores_rating  reviews_per_month
##   3   3  bedrooms  beds  review_scores_rating  reviews_per_month
##   3   4  bedrooms  beds  review_scores_rating  reviews_per_month
##   3   5  bedrooms  beds  review_scores_rating  reviews_per_month
##   4   1  bedrooms  beds  review_scores_rating  reviews_per_month
##   4   2  bedrooms  beds  review_scores_rating  reviews_per_month
##   4   3  bedrooms  beds  review_scores_rating  reviews_per_month
##   4   4  bedrooms  beds  review_scores_rating  reviews_per_month
##   4   5  bedrooms  beds  review_scores_rating  reviews_per_month
##   5   1  bedrooms  beds  review_scores_rating  reviews_per_month
##   5   2  bedrooms  beds  review_scores_rating  reviews_per_month
##   5   3  bedrooms  beds  review_scores_rating  reviews_per_month
##   5   4  bedrooms  beds  review_scores_rating  reviews_per_month
##   5   5  bedrooms  beds  review_scores_rating  reviews_per_month

Comparación de las distribuciones de los datos reemplazados con los originales:

Ahora probemos el modelo seleccionado con los datos test preparados, teniendo en cuenta las restricciones previamente definidas.

## 
## Call:
## lm(formula = log(price) ~ accommodates:district_price_group + 
##     dist_sol + +reviews_per_month:district_price_group + host_listings_count:host_is_superhost + 
##     review_scores_rating, data = data_t_m)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -1.72953 -0.27945  0.00026  0.28229  1.35027 
## 
## Coefficients:
##                                             Estimate Std. Error t value
## (Intercept)                                 3.600902   0.067176  53.604
## dist_sol                                   -0.070025   0.007250  -9.658
## review_scores_rating                        0.023952   0.007757   3.088
## accommodates:district_price_groupA          0.801610   0.080066  10.012
## accommodates:district_price_groupB          0.932118   0.016640  56.016
## accommodates:district_price_groupC          0.857868   0.011757  72.966
## accommodates:district_price_groupD          0.707342   0.017553  40.297
## accommodates:district_price_groupE          0.582922   0.036549  15.949
## district_price_groupA:reviews_per_month    -0.130530   0.062840  -2.077
## district_price_groupB:reviews_per_month    -0.041071   0.009693  -4.237
## district_price_groupC:reviews_per_month    -0.034888   0.005425  -6.431
## district_price_groupD:reviews_per_month    -0.017664   0.008786  -2.010
## district_price_groupE:reviews_per_month    -0.002891   0.019826  -0.146
## host_listings_count:host_is_superhostFALSE  0.083024   0.019136   4.339
## host_listings_count:host_is_superhostTRUE   0.205176   0.035879   5.719
##                                            Pr(>|t|)    
## (Intercept)                                 < 2e-16 ***
## dist_sol                                    < 2e-16 ***
## review_scores_rating                        0.00203 ** 
## accommodates:district_price_groupA          < 2e-16 ***
## accommodates:district_price_groupB          < 2e-16 ***
## accommodates:district_price_groupC          < 2e-16 ***
## accommodates:district_price_groupD          < 2e-16 ***
## accommodates:district_price_groupE          < 2e-16 ***
## district_price_groupA:reviews_per_month     0.03784 *  
## district_price_groupB:reviews_per_month    2.30e-05 ***
## district_price_groupC:reviews_per_month    1.39e-10 ***
## district_price_groupD:reviews_per_month     0.04443 *  
## district_price_groupE:reviews_per_month     0.88408    
## host_listings_count:host_is_superhostFALSE 1.46e-05 ***
## host_listings_count:host_is_superhostTRUE  1.14e-08 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.4244 on 5005 degrees of freedom
## Multiple R-squared:  0.6241, Adjusted R-squared:  0.623 
## F-statistic: 593.4 on 14 and 5005 DF,  p-value: < 2.2e-16
## 
## 
## ASSESSMENT OF THE LINEAR MODEL ASSUMPTIONS
## USING THE GLOBAL TEST ON 4 DEGREES-OF-FREEDOM:
## Level of Significance =  0.05 
## 
## Call:
##  gvlma(x = fit_m5) 
## 
##                      Value   p-value                   Decision
## Global Stat        21.5000 2.520e-04 Assumptions NOT satisfied!
## Skewness           17.5079 2.861e-05 Assumptions NOT satisfied!
## Kurtosis            3.6644 5.559e-02    Assumptions acceptable.
## Link Function       0.1110 7.390e-01    Assumptions acceptable.
## Heteroscedasticity  0.2167 6.416e-01    Assumptions acceptable.

En el test obtuvimos un modelo con una distribución normal de residuos.

## 
##  Lilliefors (Kolmogorov-Smirnov) normality test
## 
## data:  fit_m5$residuals
## D = 0.012233, p-value = 0.08349

Resultado y conclusiones

Como conclusión, vemos que el modelo funciona igual de bien con los datos de test que con los datos de train.

Para este modelo, en train, el valor de R² fue 0.6247.

Para test, el valor de R² fue 0.623.

##       mae       mse      rmse      mape 
## 0.3363425 0.1795832 0.4237725 0.0873607

Сomo resultado, obtuvimos un MAPE del 8,7%, que es que ligeramente peor que para el train (8,6%). Pero al mismo tiempo, el resultado es bastante bueno.

Podemos concluir que el modelo seleccionado funciona casi por igual tanto en datos de train como en datos de test.

El modelo resultante explica solo el 62,0% del precio por noche para un alojamiento (habitación individual o apartamento), con un MAPE de 8,6%. Cuando se eliminaron los valores atípicos para construir un modelo lineal, el impacto de la pandemia en los precios fue insignificante, ya que los precios fueron significativamente más altos y alcanzaron su punto máximo antes de la entrada en vigor de las restricciones. También, el relativamente bajo valor de R² sugiere que tal vez todavía haya factores que afectan significativamente al precio que no están presentes en nuestro conjunto de datos.

En el ejemplo del cálculo de valores faltantes se vio claramente que los métodos basados en random forest funcionan mejor con estos datos.